NuPlayer.cpp revision a1f8ab0ad670c30e57f3f072df13df66fe4f4910
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#include "GenericSource.h" 31#include "mp4/MP4Source.h" 32 33#include "ATSParser.h" 34 35#include <cutils/properties.h> // for property_get 36#include <media/stagefright/foundation/hexdump.h> 37#include <media/stagefright/foundation/ABuffer.h> 38#include <media/stagefright/foundation/ADebug.h> 39#include <media/stagefright/foundation/AMessage.h> 40#include <media/stagefright/ACodec.h> 41#include <media/stagefright/MediaDefs.h> 42#include <media/stagefright/MediaErrors.h> 43#include <media/stagefright/MetaData.h> 44#include <gui/ISurfaceTexture.h> 45 46#include "avc_utils.h" 47 48#include "ESDS.h" 49#include <media/stagefright/Utils.h> 50 51namespace android { 52 53struct NuPlayer::Action : public RefBase { 54 Action() {} 55 56 virtual void execute(NuPlayer *player) = 0; 57 58private: 59 DISALLOW_EVIL_CONSTRUCTORS(Action); 60}; 61 62struct NuPlayer::SeekAction : public Action { 63 SeekAction(int64_t seekTimeUs) 64 : mSeekTimeUs(seekTimeUs) { 65 } 66 67 virtual void execute(NuPlayer *player) { 68 player->performSeek(mSeekTimeUs); 69 } 70 71private: 72 int64_t mSeekTimeUs; 73 74 DISALLOW_EVIL_CONSTRUCTORS(SeekAction); 75}; 76 77// Use this if there's no state necessary to save in order to execute 78// the action. 79struct NuPlayer::SimpleAction : public Action { 80 typedef void (NuPlayer::*ActionFunc)(); 81 82 SimpleAction(ActionFunc func) 83 : mFunc(func) { 84 } 85 86 virtual void execute(NuPlayer *player) { 87 (player->*mFunc)(); 88 } 89 90private: 91 ActionFunc mFunc; 92 93 DISALLOW_EVIL_CONSTRUCTORS(SimpleAction); 94}; 95 96//////////////////////////////////////////////////////////////////////////////// 97 98NuPlayer::NuPlayer() 99 : mUIDValid(false), 100 mVideoIsAVC(false), 101 mAudioEOS(false), 102 mVideoEOS(false), 103 mScanSourcesPending(false), 104 mScanSourcesGeneration(0), 105 mPollDurationGeneration(0), 106 mTimeDiscontinuityPending(false), 107 mFlushingAudio(NONE), 108 mFlushingVideo(NONE), 109 mSkipRenderingAudioUntilMediaTimeUs(-1ll), 110 mSkipRenderingVideoUntilMediaTimeUs(-1ll), 111 mVideoLateByUs(0ll), 112 mNumFramesTotal(0ll), 113 mNumFramesDropped(0ll), 114 mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW) { 115} 116 117NuPlayer::~NuPlayer() { 118} 119 120void NuPlayer::setUID(uid_t uid) { 121 mUIDValid = true; 122 mUID = uid; 123} 124 125void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) { 126 mDriver = driver; 127} 128 129void NuPlayer::setDataSource(const sp<IStreamSource> &source) { 130 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 131 132 char prop[PROPERTY_VALUE_MAX]; 133 if (property_get("media.stagefright.use-mp4source", prop, NULL) 134 && (!strcmp(prop, "1") || !strcasecmp(prop, "true"))) { 135 msg->setObject("source", new MP4Source(source)); 136 } else { 137 msg->setObject("source", new StreamingSource(source)); 138 } 139 140 msg->post(); 141} 142 143static bool IsHTTPLiveURL(const char *url) { 144 if (!strncasecmp("http://", url, 7) 145 || !strncasecmp("https://", url, 8)) { 146 size_t len = strlen(url); 147 if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) { 148 return true; 149 } 150 151 if (strstr(url,"m3u8")) { 152 return true; 153 } 154 } 155 156 return false; 157} 158 159void NuPlayer::setDataSource( 160 const char *url, const KeyedVector<String8, String8> *headers) { 161 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 162 163 sp<Source> source; 164 if (IsHTTPLiveURL(url)) { 165 source = new HTTPLiveSource(url, headers, mUIDValid, mUID); 166 } else if (!strncasecmp(url, "rtsp://", 7)) { 167 source = new RTSPSource(url, headers, mUIDValid, mUID); 168 } else { 169 source = new GenericSource(url, headers, mUIDValid, mUID); 170 } 171 172 msg->setObject("source", source); 173 msg->post(); 174} 175 176void NuPlayer::setDataSource(int fd, int64_t offset, int64_t length) { 177 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 178 179 sp<Source> source = new GenericSource(fd, offset, length); 180 msg->setObject("source", source); 181 msg->post(); 182} 183 184void NuPlayer::setVideoSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 185 sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id()); 186 sp<SurfaceTextureClient> surfaceTextureClient(surfaceTexture != NULL ? 187 new SurfaceTextureClient(surfaceTexture) : NULL); 188 msg->setObject("native-window", new NativeWindowWrapper(surfaceTextureClient)); 189 msg->post(); 190} 191 192void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) { 193 sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id()); 194 msg->setObject("sink", sink); 195 msg->post(); 196} 197 198void NuPlayer::start() { 199 (new AMessage(kWhatStart, id()))->post(); 200} 201 202void NuPlayer::pause() { 203 (new AMessage(kWhatPause, id()))->post(); 204} 205 206void NuPlayer::resume() { 207 (new AMessage(kWhatResume, id()))->post(); 208} 209 210void NuPlayer::resetAsync() { 211 (new AMessage(kWhatReset, id()))->post(); 212} 213 214void NuPlayer::seekToAsync(int64_t seekTimeUs) { 215 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 216 msg->setInt64("seekTimeUs", seekTimeUs); 217 msg->post(); 218} 219 220// static 221bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) { 222 switch (state) { 223 case FLUSHING_DECODER: 224 if (needShutdown != NULL) { 225 *needShutdown = false; 226 } 227 return true; 228 229 case FLUSHING_DECODER_SHUTDOWN: 230 if (needShutdown != NULL) { 231 *needShutdown = true; 232 } 233 return true; 234 235 default: 236 return false; 237 } 238} 239 240void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { 241 switch (msg->what()) { 242 case kWhatSetDataSource: 243 { 244 ALOGV("kWhatSetDataSource"); 245 246 CHECK(mSource == NULL); 247 248 sp<RefBase> obj; 249 CHECK(msg->findObject("source", &obj)); 250 251 mSource = static_cast<Source *>(obj.get()); 252 break; 253 } 254 255 case kWhatPollDuration: 256 { 257 int32_t generation; 258 CHECK(msg->findInt32("generation", &generation)); 259 260 if (generation != mPollDurationGeneration) { 261 // stale 262 break; 263 } 264 265 int64_t durationUs; 266 if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { 267 sp<NuPlayerDriver> driver = mDriver.promote(); 268 if (driver != NULL) { 269 driver->notifyDuration(durationUs); 270 } 271 } 272 273 msg->post(1000000ll); // poll again in a second. 274 break; 275 } 276 277 case kWhatSetVideoNativeWindow: 278 { 279 ALOGV("kWhatSetVideoNativeWindow"); 280 281 sp<RefBase> obj; 282 CHECK(msg->findObject("native-window", &obj)); 283 284 mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get()); 285 286 // XXX - ignore error from setVideoScalingMode for now 287 setVideoScalingMode(mVideoScalingMode); 288 break; 289 } 290 291 case kWhatSetAudioSink: 292 { 293 ALOGV("kWhatSetAudioSink"); 294 295 sp<RefBase> obj; 296 CHECK(msg->findObject("sink", &obj)); 297 298 mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); 299 break; 300 } 301 302 case kWhatStart: 303 { 304 ALOGV("kWhatStart"); 305 306 mVideoIsAVC = false; 307 mAudioEOS = false; 308 mVideoEOS = false; 309 mSkipRenderingAudioUntilMediaTimeUs = -1; 310 mSkipRenderingVideoUntilMediaTimeUs = -1; 311 mVideoLateByUs = 0; 312 mNumFramesTotal = 0; 313 mNumFramesDropped = 0; 314 315 mSource->start(); 316 317 mRenderer = new Renderer( 318 mAudioSink, 319 new AMessage(kWhatRendererNotify, id())); 320 321 looper()->registerHandler(mRenderer); 322 323 postScanSources(); 324 break; 325 } 326 327 case kWhatScanSources: 328 { 329 int32_t generation; 330 CHECK(msg->findInt32("generation", &generation)); 331 if (generation != mScanSourcesGeneration) { 332 // Drop obsolete msg. 333 break; 334 } 335 336 mScanSourcesPending = false; 337 338 ALOGV("scanning sources haveAudio=%d, haveVideo=%d", 339 mAudioDecoder != NULL, mVideoDecoder != NULL); 340 341 bool mHadAnySourcesBefore = 342 (mAudioDecoder != NULL) || (mVideoDecoder != NULL); 343 344 if (mNativeWindow != NULL) { 345 instantiateDecoder(false, &mVideoDecoder); 346 } 347 348 if (mAudioSink != NULL) { 349 instantiateDecoder(true, &mAudioDecoder); 350 } 351 352 if (!mHadAnySourcesBefore 353 && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { 354 // This is the first time we've found anything playable. 355 356 uint32_t flags = mSource->flags(); 357 358 if (flags & Source::FLAG_DYNAMIC_DURATION) { 359 schedulePollDuration(); 360 } 361 } 362 363 status_t err; 364 if ((err = mSource->feedMoreTSData()) != OK) { 365 if (mAudioDecoder == NULL && mVideoDecoder == NULL) { 366 // We're not currently decoding anything (no audio or 367 // video tracks found) and we just ran out of input data. 368 369 if (err == ERROR_END_OF_STREAM) { 370 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 371 } else { 372 notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 373 } 374 } 375 break; 376 } 377 378 if ((mAudioDecoder == NULL && mAudioSink != NULL) 379 || (mVideoDecoder == NULL && mNativeWindow != NULL)) { 380 msg->post(100000ll); 381 mScanSourcesPending = true; 382 } 383 break; 384 } 385 386 case kWhatVideoNotify: 387 case kWhatAudioNotify: 388 { 389 bool audio = msg->what() == kWhatAudioNotify; 390 391 sp<AMessage> codecRequest; 392 CHECK(msg->findMessage("codec-request", &codecRequest)); 393 394 int32_t what; 395 CHECK(codecRequest->findInt32("what", &what)); 396 397 if (what == ACodec::kWhatFillThisBuffer) { 398 status_t err = feedDecoderInputData( 399 audio, codecRequest); 400 401 if (err == -EWOULDBLOCK) { 402 if (mSource->feedMoreTSData() == OK) { 403 msg->post(10000ll); 404 } 405 } 406 } else if (what == ACodec::kWhatEOS) { 407 int32_t err; 408 CHECK(codecRequest->findInt32("err", &err)); 409 410 if (err == ERROR_END_OF_STREAM) { 411 ALOGV("got %s decoder EOS", audio ? "audio" : "video"); 412 } else { 413 ALOGV("got %s decoder EOS w/ error %d", 414 audio ? "audio" : "video", 415 err); 416 } 417 418 mRenderer->queueEOS(audio, err); 419 } else if (what == ACodec::kWhatFlushCompleted) { 420 bool needShutdown; 421 422 if (audio) { 423 CHECK(IsFlushingState(mFlushingAudio, &needShutdown)); 424 mFlushingAudio = FLUSHED; 425 } else { 426 CHECK(IsFlushingState(mFlushingVideo, &needShutdown)); 427 mFlushingVideo = FLUSHED; 428 429 mVideoLateByUs = 0; 430 } 431 432 ALOGV("decoder %s flush completed", audio ? "audio" : "video"); 433 434 if (needShutdown) { 435 ALOGV("initiating %s decoder shutdown", 436 audio ? "audio" : "video"); 437 438 (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); 439 440 if (audio) { 441 mFlushingAudio = SHUTTING_DOWN_DECODER; 442 } else { 443 mFlushingVideo = SHUTTING_DOWN_DECODER; 444 } 445 } 446 447 finishFlushIfPossible(); 448 } else if (what == ACodec::kWhatOutputFormatChanged) { 449 if (audio) { 450 int32_t numChannels; 451 CHECK(codecRequest->findInt32("channel-count", &numChannels)); 452 453 int32_t sampleRate; 454 CHECK(codecRequest->findInt32("sample-rate", &sampleRate)); 455 456 ALOGV("Audio output format changed to %d Hz, %d channels", 457 sampleRate, numChannels); 458 459 mAudioSink->close(); 460 461 audio_output_flags_t flags; 462 int64_t durationUs; 463 // FIXME: we should handle the case where the video decoder is created after 464 // we receive the format change indication. Current code will just make that 465 // we select deep buffer with video which should not be a problem as it should 466 // not prevent from keeping A/V sync. 467 if (mVideoDecoder == NULL && 468 mSource->getDuration(&durationUs) == OK && 469 durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { 470 flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; 471 } else { 472 flags = AUDIO_OUTPUT_FLAG_NONE; 473 } 474 475 int32_t channelMask; 476 if (!codecRequest->findInt32("channel-mask", &channelMask)) { 477 channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; 478 } 479 480 CHECK_EQ(mAudioSink->open( 481 sampleRate, 482 numChannels, 483 (audio_channel_mask_t)channelMask, 484 AUDIO_FORMAT_PCM_16_BIT, 485 8 /* bufferCount */, 486 NULL, 487 NULL, 488 flags), 489 (status_t)OK); 490 mAudioSink->start(); 491 492 mRenderer->signalAudioSinkChanged(); 493 } else { 494 // video 495 496 int32_t width, height; 497 CHECK(codecRequest->findInt32("width", &width)); 498 CHECK(codecRequest->findInt32("height", &height)); 499 500 int32_t cropLeft, cropTop, cropRight, cropBottom; 501 CHECK(codecRequest->findRect( 502 "crop", 503 &cropLeft, &cropTop, &cropRight, &cropBottom)); 504 505 ALOGV("Video output format changed to %d x %d " 506 "(crop: %d x %d @ (%d, %d))", 507 width, height, 508 (cropRight - cropLeft + 1), 509 (cropBottom - cropTop + 1), 510 cropLeft, cropTop); 511 512 notifyListener( 513 MEDIA_SET_VIDEO_SIZE, 514 cropRight - cropLeft + 1, 515 cropBottom - cropTop + 1); 516 } 517 } else if (what == ACodec::kWhatShutdownCompleted) { 518 ALOGV("%s shutdown completed", audio ? "audio" : "video"); 519 if (audio) { 520 mAudioDecoder.clear(); 521 522 CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); 523 mFlushingAudio = SHUT_DOWN; 524 } else { 525 mVideoDecoder.clear(); 526 527 CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); 528 mFlushingVideo = SHUT_DOWN; 529 } 530 531 finishFlushIfPossible(); 532 } else if (what == ACodec::kWhatError) { 533 ALOGE("Received error from %s decoder, aborting playback.", 534 audio ? "audio" : "video"); 535 536 mRenderer->queueEOS(audio, UNKNOWN_ERROR); 537 } else if (what == ACodec::kWhatDrainThisBuffer) { 538 renderBuffer(audio, codecRequest); 539 } else if (what != ACodec::kWhatComponentAllocated 540 && what != ACodec::kWhatComponentConfigured 541 && what != ACodec::kWhatBuffersAllocated) { 542 ALOGV("Unhandled codec notification %d '%c%c%c%c'.", 543 what, 544 what >> 24, 545 (what >> 16) & 0xff, 546 (what >> 8) & 0xff, 547 what & 0xff); 548 } 549 550 break; 551 } 552 553 case kWhatRendererNotify: 554 { 555 int32_t what; 556 CHECK(msg->findInt32("what", &what)); 557 558 if (what == Renderer::kWhatEOS) { 559 int32_t audio; 560 CHECK(msg->findInt32("audio", &audio)); 561 562 int32_t finalResult; 563 CHECK(msg->findInt32("finalResult", &finalResult)); 564 565 if (audio) { 566 mAudioEOS = true; 567 } else { 568 mVideoEOS = true; 569 } 570 571 if (finalResult == ERROR_END_OF_STREAM) { 572 ALOGV("reached %s EOS", audio ? "audio" : "video"); 573 } else { 574 ALOGE("%s track encountered an error (%d)", 575 audio ? "audio" : "video", finalResult); 576 577 notifyListener( 578 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult); 579 } 580 581 if ((mAudioEOS || mAudioDecoder == NULL) 582 && (mVideoEOS || mVideoDecoder == NULL)) { 583 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 584 } 585 } else if (what == Renderer::kWhatPosition) { 586 int64_t positionUs; 587 CHECK(msg->findInt64("positionUs", &positionUs)); 588 589 CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); 590 591 if (mDriver != NULL) { 592 sp<NuPlayerDriver> driver = mDriver.promote(); 593 if (driver != NULL) { 594 driver->notifyPosition(positionUs); 595 596 driver->notifyFrameStats( 597 mNumFramesTotal, mNumFramesDropped); 598 } 599 } 600 } else if (what == Renderer::kWhatFlushComplete) { 601 int32_t audio; 602 CHECK(msg->findInt32("audio", &audio)); 603 604 ALOGV("renderer %s flush completed.", audio ? "audio" : "video"); 605 } else if (what == Renderer::kWhatVideoRenderingStart) { 606 notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0); 607 } 608 break; 609 } 610 611 case kWhatMoreDataQueued: 612 { 613 break; 614 } 615 616 case kWhatReset: 617 { 618 ALOGV("kWhatReset"); 619 620 mDeferredActions.push_back( 621 new SimpleAction(&NuPlayer::performDecoderShutdown)); 622 623 mDeferredActions.push_back( 624 new SimpleAction(&NuPlayer::performReset)); 625 626 processDeferredActions(); 627 break; 628 } 629 630 case kWhatSeek: 631 { 632 int64_t seekTimeUs; 633 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 634 635 ALOGV("kWhatSeek seekTimeUs=%lld us", seekTimeUs); 636 637 mDeferredActions.push_back( 638 new SimpleAction(&NuPlayer::performDecoderFlush)); 639 640 mDeferredActions.push_back(new SeekAction(seekTimeUs)); 641 642 processDeferredActions(); 643 break; 644 } 645 646 case kWhatPause: 647 { 648 CHECK(mRenderer != NULL); 649 mRenderer->pause(); 650 break; 651 } 652 653 case kWhatResume: 654 { 655 CHECK(mRenderer != NULL); 656 mRenderer->resume(); 657 break; 658 } 659 660 default: 661 TRESPASS(); 662 break; 663 } 664} 665 666void NuPlayer::finishFlushIfPossible() { 667 if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) { 668 return; 669 } 670 671 if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) { 672 return; 673 } 674 675 ALOGV("both audio and video are flushed now."); 676 677 if (mTimeDiscontinuityPending) { 678 mRenderer->signalTimeDiscontinuity(); 679 mTimeDiscontinuityPending = false; 680 } 681 682 if (mAudioDecoder != NULL) { 683 mAudioDecoder->signalResume(); 684 } 685 686 if (mVideoDecoder != NULL) { 687 mVideoDecoder->signalResume(); 688 } 689 690 mFlushingAudio = NONE; 691 mFlushingVideo = NONE; 692 693 processDeferredActions(); 694} 695 696void NuPlayer::postScanSources() { 697 if (mScanSourcesPending) { 698 return; 699 } 700 701 sp<AMessage> msg = new AMessage(kWhatScanSources, id()); 702 msg->setInt32("generation", mScanSourcesGeneration); 703 msg->post(); 704 705 mScanSourcesPending = true; 706} 707 708status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { 709 if (*decoder != NULL) { 710 return OK; 711 } 712 713 sp<AMessage> format = mSource->getFormat(audio); 714 715 if (format == NULL) { 716 return -EWOULDBLOCK; 717 } 718 719 if (!audio) { 720 AString mime; 721 CHECK(format->findString("mime", &mime)); 722 mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str()); 723 } 724 725 sp<AMessage> notify = 726 new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify, 727 id()); 728 729 *decoder = audio ? new Decoder(notify) : 730 new Decoder(notify, mNativeWindow); 731 looper()->registerHandler(*decoder); 732 733 (*decoder)->configure(format); 734 735 int64_t durationUs; 736 if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { 737 sp<NuPlayerDriver> driver = mDriver.promote(); 738 if (driver != NULL) { 739 driver->notifyDuration(durationUs); 740 } 741 } 742 743 return OK; 744} 745 746status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { 747 sp<AMessage> reply; 748 CHECK(msg->findMessage("reply", &reply)); 749 750 if ((audio && IsFlushingState(mFlushingAudio)) 751 || (!audio && IsFlushingState(mFlushingVideo))) { 752 reply->setInt32("err", INFO_DISCONTINUITY); 753 reply->post(); 754 return OK; 755 } 756 757 sp<ABuffer> accessUnit; 758 759 bool dropAccessUnit; 760 do { 761 status_t err = mSource->dequeueAccessUnit(audio, &accessUnit); 762 763 if (err == -EWOULDBLOCK) { 764 return err; 765 } else if (err != OK) { 766 if (err == INFO_DISCONTINUITY) { 767 int32_t type; 768 CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); 769 770 bool formatChange = 771 (audio && 772 (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT)) 773 || (!audio && 774 (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT)); 775 776 bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0; 777 778 ALOGI("%s discontinuity (formatChange=%d, time=%d)", 779 audio ? "audio" : "video", formatChange, timeChange); 780 781 if (audio) { 782 mSkipRenderingAudioUntilMediaTimeUs = -1; 783 } else { 784 mSkipRenderingVideoUntilMediaTimeUs = -1; 785 } 786 787 if (timeChange) { 788 sp<AMessage> extra; 789 if (accessUnit->meta()->findMessage("extra", &extra) 790 && extra != NULL) { 791 int64_t resumeAtMediaTimeUs; 792 if (extra->findInt64( 793 "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { 794 ALOGI("suppressing rendering of %s until %lld us", 795 audio ? "audio" : "video", resumeAtMediaTimeUs); 796 797 if (audio) { 798 mSkipRenderingAudioUntilMediaTimeUs = 799 resumeAtMediaTimeUs; 800 } else { 801 mSkipRenderingVideoUntilMediaTimeUs = 802 resumeAtMediaTimeUs; 803 } 804 } 805 } 806 } 807 808 mTimeDiscontinuityPending = 809 mTimeDiscontinuityPending || timeChange; 810 811 if (formatChange || timeChange) { 812 if (mFlushingAudio == NONE && mFlushingVideo == NONE) { 813 // And we'll resume scanning sources once we're done 814 // flushing. 815 mDeferredActions.push_front( 816 new SimpleAction( 817 &NuPlayer::performScanSources)); 818 } 819 820 flushDecoder(audio, formatChange); 821 } else { 822 // This stream is unaffected by the discontinuity 823 824 if (audio) { 825 mFlushingAudio = FLUSHED; 826 } else { 827 mFlushingVideo = FLUSHED; 828 } 829 830 finishFlushIfPossible(); 831 832 return -EWOULDBLOCK; 833 } 834 } 835 836 reply->setInt32("err", err); 837 reply->post(); 838 return OK; 839 } 840 841 if (!audio) { 842 ++mNumFramesTotal; 843 } 844 845 dropAccessUnit = false; 846 if (!audio 847 && mVideoLateByUs > 100000ll 848 && mVideoIsAVC 849 && !IsAVCReferenceFrame(accessUnit)) { 850 dropAccessUnit = true; 851 ++mNumFramesDropped; 852 } 853 } while (dropAccessUnit); 854 855 // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); 856 857#if 0 858 int64_t mediaTimeUs; 859 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); 860 ALOGV("feeding %s input buffer at media time %.2f secs", 861 audio ? "audio" : "video", 862 mediaTimeUs / 1E6); 863#endif 864 865 reply->setBuffer("buffer", accessUnit); 866 reply->post(); 867 868 return OK; 869} 870 871void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { 872 // ALOGV("renderBuffer %s", audio ? "audio" : "video"); 873 874 sp<AMessage> reply; 875 CHECK(msg->findMessage("reply", &reply)); 876 877 if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) { 878 // We're currently attempting to flush the decoder, in order 879 // to complete this, the decoder wants all its buffers back, 880 // so we don't want any output buffers it sent us (from before 881 // we initiated the flush) to be stuck in the renderer's queue. 882 883 ALOGV("we're still flushing the %s decoder, sending its output buffer" 884 " right back.", audio ? "audio" : "video"); 885 886 reply->post(); 887 return; 888 } 889 890 sp<ABuffer> buffer; 891 CHECK(msg->findBuffer("buffer", &buffer)); 892 893 int64_t &skipUntilMediaTimeUs = 894 audio 895 ? mSkipRenderingAudioUntilMediaTimeUs 896 : mSkipRenderingVideoUntilMediaTimeUs; 897 898 if (skipUntilMediaTimeUs >= 0) { 899 int64_t mediaTimeUs; 900 CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); 901 902 if (mediaTimeUs < skipUntilMediaTimeUs) { 903 ALOGV("dropping %s buffer at time %lld as requested.", 904 audio ? "audio" : "video", 905 mediaTimeUs); 906 907 reply->post(); 908 return; 909 } 910 911 skipUntilMediaTimeUs = -1; 912 } 913 914 mRenderer->queueBuffer(audio, buffer, reply); 915} 916 917void NuPlayer::notifyListener(int msg, int ext1, int ext2) { 918 if (mDriver == NULL) { 919 return; 920 } 921 922 sp<NuPlayerDriver> driver = mDriver.promote(); 923 924 if (driver == NULL) { 925 return; 926 } 927 928 driver->notifyListener(msg, ext1, ext2); 929} 930 931void NuPlayer::flushDecoder(bool audio, bool needShutdown) { 932 if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) { 933 ALOGI("flushDecoder %s without decoder present", 934 audio ? "audio" : "video"); 935 } 936 937 // Make sure we don't continue to scan sources until we finish flushing. 938 ++mScanSourcesGeneration; 939 mScanSourcesPending = false; 940 941 (audio ? mAudioDecoder : mVideoDecoder)->signalFlush(); 942 mRenderer->flush(audio); 943 944 FlushStatus newStatus = 945 needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER; 946 947 if (audio) { 948 CHECK(mFlushingAudio == NONE 949 || mFlushingAudio == AWAITING_DISCONTINUITY); 950 951 mFlushingAudio = newStatus; 952 953 if (mFlushingVideo == NONE) { 954 mFlushingVideo = (mVideoDecoder != NULL) 955 ? AWAITING_DISCONTINUITY 956 : FLUSHED; 957 } 958 } else { 959 CHECK(mFlushingVideo == NONE 960 || mFlushingVideo == AWAITING_DISCONTINUITY); 961 962 mFlushingVideo = newStatus; 963 964 if (mFlushingAudio == NONE) { 965 mFlushingAudio = (mAudioDecoder != NULL) 966 ? AWAITING_DISCONTINUITY 967 : FLUSHED; 968 } 969 } 970} 971 972sp<AMessage> NuPlayer::Source::getFormat(bool audio) { 973 sp<MetaData> meta = getFormatMeta(audio); 974 975 if (meta == NULL) { 976 return NULL; 977 } 978 979 sp<AMessage> msg = new AMessage; 980 981 if(convertMetaDataToMessage(meta, &msg) == OK) { 982 return msg; 983 } 984 return NULL; 985} 986 987status_t NuPlayer::setVideoScalingMode(int32_t mode) { 988 mVideoScalingMode = mode; 989 if (mNativeWindow != NULL 990 && mNativeWindow->getNativeWindow() != NULL) { 991 status_t ret = native_window_set_scaling_mode( 992 mNativeWindow->getNativeWindow().get(), mVideoScalingMode); 993 if (ret != OK) { 994 ALOGE("Failed to set scaling mode (%d): %s", 995 -ret, strerror(-ret)); 996 return ret; 997 } 998 } 999 return OK; 1000} 1001 1002void NuPlayer::schedulePollDuration() { 1003 sp<AMessage> msg = new AMessage(kWhatPollDuration, id()); 1004 msg->setInt32("generation", mPollDurationGeneration); 1005 msg->post(); 1006} 1007 1008void NuPlayer::cancelPollDuration() { 1009 ++mPollDurationGeneration; 1010} 1011 1012void NuPlayer::processDeferredActions() { 1013 while (!mDeferredActions.empty()) { 1014 // We won't execute any deferred actions until we're no longer in 1015 // an intermediate state, i.e. one more more decoders are currently 1016 // flushing or shutting down. 1017 1018 if (mRenderer != NULL) { 1019 // There's an edge case where the renderer owns all output 1020 // buffers and is paused, therefore the decoder will not read 1021 // more input data and will never encounter the matching 1022 // discontinuity. To avoid this, we resume the renderer. 1023 1024 if (mFlushingAudio == AWAITING_DISCONTINUITY 1025 || mFlushingVideo == AWAITING_DISCONTINUITY) { 1026 mRenderer->resume(); 1027 } 1028 } 1029 1030 if (mFlushingAudio != NONE || mFlushingVideo != NONE) { 1031 // We're currently flushing, postpone the reset until that's 1032 // completed. 1033 1034 ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d", 1035 mFlushingAudio, mFlushingVideo); 1036 1037 break; 1038 } 1039 1040 sp<Action> action = *mDeferredActions.begin(); 1041 mDeferredActions.erase(mDeferredActions.begin()); 1042 1043 action->execute(this); 1044 } 1045} 1046 1047void NuPlayer::performSeek(int64_t seekTimeUs) { 1048 ALOGV("performSeek seekTimeUs=%lld us (%.2f secs)", 1049 seekTimeUs, 1050 seekTimeUs / 1E6); 1051 1052 mSource->seekTo(seekTimeUs); 1053 1054 if (mDriver != NULL) { 1055 sp<NuPlayerDriver> driver = mDriver.promote(); 1056 if (driver != NULL) { 1057 driver->notifyPosition(seekTimeUs); 1058 driver->notifySeekComplete(); 1059 } 1060 } 1061 1062 // everything's flushed, continue playback. 1063} 1064 1065void NuPlayer::performDecoderFlush() { 1066 ALOGV("performDecoderFlush"); 1067 1068 if (mAudioDecoder != NULL && mVideoDecoder == NULL) { 1069 return; 1070 } 1071 1072 mTimeDiscontinuityPending = true; 1073 1074 if (mAudioDecoder != NULL) { 1075 flushDecoder(true /* audio */, false /* needShutdown */); 1076 } 1077 1078 if (mVideoDecoder != NULL) { 1079 flushDecoder(false /* audio */, false /* needShutdown */); 1080 } 1081} 1082 1083void NuPlayer::performDecoderShutdown() { 1084 ALOGV("performDecoderShutdown"); 1085 1086 if (mAudioDecoder != NULL && mVideoDecoder == NULL) { 1087 return; 1088 } 1089 1090 mTimeDiscontinuityPending = true; 1091 1092 if (mAudioDecoder != NULL) { 1093 flushDecoder(true /* audio */, true /* needShutdown */); 1094 } 1095 1096 if (mVideoDecoder != NULL) { 1097 flushDecoder(false /* audio */, true /* needShutdown */); 1098 } 1099} 1100 1101void NuPlayer::performReset() { 1102 ALOGV("performReset"); 1103 1104 CHECK(mAudioDecoder == NULL); 1105 CHECK(mVideoDecoder == NULL); 1106 1107 cancelPollDuration(); 1108 1109 ++mScanSourcesGeneration; 1110 mScanSourcesPending = false; 1111 1112 mRenderer.clear(); 1113 1114 if (mSource != NULL) { 1115 mSource->stop(); 1116 mSource.clear(); 1117 } 1118 1119 if (mDriver != NULL) { 1120 sp<NuPlayerDriver> driver = mDriver.promote(); 1121 if (driver != NULL) { 1122 driver->notifyResetComplete(); 1123 } 1124 } 1125} 1126 1127void NuPlayer::performScanSources() { 1128 ALOGV("performScanSources"); 1129 1130 if (mAudioDecoder == NULL || mVideoDecoder == NULL) { 1131 postScanSources(); 1132 } 1133} 1134 1135} // namespace android 1136