NuPlayer.cpp revision 404fced9bfa8fa423ee210a271ca051ffd1bec13
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 32#include "ATSParser.h" 33 34#include <media/stagefright/foundation/hexdump.h> 35#include <media/stagefright/foundation/ABuffer.h> 36#include <media/stagefright/foundation/ADebug.h> 37#include <media/stagefright/foundation/AMessage.h> 38#include <media/stagefright/MediaDefs.h> 39#include <media/stagefright/MediaErrors.h> 40#include <media/stagefright/MetaData.h> 41#include <gui/IGraphicBufferProducer.h> 42 43#include "avc_utils.h" 44 45#include "ESDS.h" 46#include <media/stagefright/Utils.h> 47 48namespace android { 49 50struct NuPlayer::Action : public RefBase { 51 Action() {} 52 53 virtual void execute(NuPlayer *player) = 0; 54 55private: 56 DISALLOW_EVIL_CONSTRUCTORS(Action); 57}; 58 59struct NuPlayer::SeekAction : public Action { 60 SeekAction(int64_t seekTimeUs) 61 : mSeekTimeUs(seekTimeUs) { 62 } 63 64 virtual void execute(NuPlayer *player) { 65 player->performSeek(mSeekTimeUs); 66 } 67 68private: 69 int64_t mSeekTimeUs; 70 71 DISALLOW_EVIL_CONSTRUCTORS(SeekAction); 72}; 73 74struct NuPlayer::SetSurfaceAction : public Action { 75 SetSurfaceAction(const sp<NativeWindowWrapper> &wrapper) 76 : mWrapper(wrapper) { 77 } 78 79 virtual void execute(NuPlayer *player) { 80 player->performSetSurface(mWrapper); 81 } 82 83private: 84 sp<NativeWindowWrapper> mWrapper; 85 86 DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction); 87}; 88 89struct NuPlayer::ShutdownDecoderAction : public Action { 90 ShutdownDecoderAction(bool audio, bool video) 91 : mAudio(audio), 92 mVideo(video) { 93 } 94 95 virtual void execute(NuPlayer *player) { 96 player->performDecoderShutdown(mAudio, mVideo); 97 } 98 99private: 100 bool mAudio; 101 bool mVideo; 102 103 DISALLOW_EVIL_CONSTRUCTORS(ShutdownDecoderAction); 104}; 105 106struct NuPlayer::PostMessageAction : public Action { 107 PostMessageAction(const sp<AMessage> &msg) 108 : mMessage(msg) { 109 } 110 111 virtual void execute(NuPlayer *) { 112 mMessage->post(); 113 } 114 115private: 116 sp<AMessage> mMessage; 117 118 DISALLOW_EVIL_CONSTRUCTORS(PostMessageAction); 119}; 120 121// Use this if there's no state necessary to save in order to execute 122// the action. 123struct NuPlayer::SimpleAction : public Action { 124 typedef void (NuPlayer::*ActionFunc)(); 125 126 SimpleAction(ActionFunc func) 127 : mFunc(func) { 128 } 129 130 virtual void execute(NuPlayer *player) { 131 (player->*mFunc)(); 132 } 133 134private: 135 ActionFunc mFunc; 136 137 DISALLOW_EVIL_CONSTRUCTORS(SimpleAction); 138}; 139 140//////////////////////////////////////////////////////////////////////////////// 141 142NuPlayer::NuPlayer() 143 : mUIDValid(false), 144 mSourceFlags(0), 145 mVideoIsAVC(false), 146 mAudioEOS(false), 147 mVideoEOS(false), 148 mScanSourcesPending(false), 149 mScanSourcesGeneration(0), 150 mPollDurationGeneration(0), 151 mTimeDiscontinuityPending(false), 152 mFlushingAudio(NONE), 153 mFlushingVideo(NONE), 154 mSkipRenderingAudioUntilMediaTimeUs(-1ll), 155 mSkipRenderingVideoUntilMediaTimeUs(-1ll), 156 mVideoLateByUs(0ll), 157 mNumFramesTotal(0ll), 158 mNumFramesDropped(0ll), 159 mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW), 160 mStarted(false) { 161} 162 163NuPlayer::~NuPlayer() { 164} 165 166void NuPlayer::setUID(uid_t uid) { 167 mUIDValid = true; 168 mUID = uid; 169} 170 171void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) { 172 mDriver = driver; 173} 174 175void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) { 176 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 177 178 sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); 179 180 msg->setObject("source", new StreamingSource(notify, source)); 181 msg->post(); 182} 183 184static bool IsHTTPLiveURL(const char *url) { 185 if (!strncasecmp("http://", url, 7) 186 || !strncasecmp("https://", url, 8) 187 || !strncasecmp("file://", url, 7)) { 188 size_t len = strlen(url); 189 if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) { 190 return true; 191 } 192 193 if (strstr(url,"m3u8")) { 194 return true; 195 } 196 } 197 198 return false; 199} 200 201void NuPlayer::setDataSourceAsync( 202 const sp<IMediaHTTPService> &httpService, 203 const char *url, 204 const KeyedVector<String8, String8> *headers) { 205 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 206 size_t len = strlen(url); 207 208 sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); 209 210 sp<Source> source; 211 if (IsHTTPLiveURL(url)) { 212 source = new HTTPLiveSource(notify, httpService, url, headers); 213 } else if (!strncasecmp(url, "rtsp://", 7)) { 214 source = new RTSPSource( 215 notify, httpService, url, headers, mUIDValid, mUID); 216 } else if ((!strncasecmp(url, "http://", 7) 217 || !strncasecmp(url, "https://", 8)) 218 && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) 219 || strstr(url, ".sdp?"))) { 220 source = new RTSPSource( 221 notify, httpService, url, headers, mUIDValid, mUID, true); 222 } else { 223 source = new GenericSource(notify, httpService, url, headers); 224 } 225 226 msg->setObject("source", source); 227 msg->post(); 228} 229 230void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) { 231 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 232 233 sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); 234 235 sp<Source> source = new GenericSource(notify, fd, offset, length); 236 msg->setObject("source", source); 237 msg->post(); 238} 239 240void NuPlayer::prepareAsync() { 241 (new AMessage(kWhatPrepare, id()))->post(); 242} 243 244void NuPlayer::setVideoSurfaceTextureAsync( 245 const sp<IGraphicBufferProducer> &bufferProducer) { 246 sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id()); 247 248 if (bufferProducer == NULL) { 249 msg->setObject("native-window", NULL); 250 } else { 251 msg->setObject( 252 "native-window", 253 new NativeWindowWrapper( 254 new Surface(bufferProducer))); 255 } 256 257 msg->post(); 258} 259 260void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) { 261 sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id()); 262 msg->setObject("sink", sink); 263 msg->post(); 264} 265 266void NuPlayer::start() { 267 (new AMessage(kWhatStart, id()))->post(); 268} 269 270void NuPlayer::pause() { 271 (new AMessage(kWhatPause, id()))->post(); 272} 273 274void NuPlayer::resume() { 275 (new AMessage(kWhatResume, id()))->post(); 276} 277 278void NuPlayer::resetAsync() { 279 (new AMessage(kWhatReset, id()))->post(); 280} 281 282void NuPlayer::seekToAsync(int64_t seekTimeUs) { 283 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 284 msg->setInt64("seekTimeUs", seekTimeUs); 285 msg->post(); 286} 287 288// static 289bool NuPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) { 290 switch (state) { 291 case FLUSHING_DECODER: 292 if (needShutdown != NULL) { 293 *needShutdown = false; 294 } 295 return true; 296 297 case FLUSHING_DECODER_SHUTDOWN: 298 if (needShutdown != NULL) { 299 *needShutdown = true; 300 } 301 return true; 302 303 default: 304 return false; 305 } 306} 307 308void NuPlayer::writeTrackInfo( 309 Parcel* reply, const sp<AMessage> format) const { 310 int32_t trackType; 311 CHECK(format->findInt32("type", &trackType)); 312 313 AString lang; 314 CHECK(format->findString("language", &lang)); 315 316 reply->writeInt32(2); // write something non-zero 317 reply->writeInt32(trackType); 318 reply->writeString16(String16(lang.c_str())); 319 320 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 321 AString mime; 322 CHECK(format->findString("mime", &mime)); 323 324 int32_t isAuto, isDefault, isForced; 325 CHECK(format->findInt32("auto", &isAuto)); 326 CHECK(format->findInt32("default", &isDefault)); 327 CHECK(format->findInt32("forced", &isForced)); 328 329 reply->writeString16(String16(mime.c_str())); 330 reply->writeInt32(isAuto); 331 reply->writeInt32(isDefault); 332 reply->writeInt32(isForced); 333 } 334} 335 336void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { 337 switch (msg->what()) { 338 case kWhatSetDataSource: 339 { 340 ALOGV("kWhatSetDataSource"); 341 342 CHECK(mSource == NULL); 343 344 sp<RefBase> obj; 345 CHECK(msg->findObject("source", &obj)); 346 347 mSource = static_cast<Source *>(obj.get()); 348 349 looper()->registerHandler(mSource); 350 351 CHECK(mDriver != NULL); 352 sp<NuPlayerDriver> driver = mDriver.promote(); 353 if (driver != NULL) { 354 driver->notifySetDataSourceCompleted(OK); 355 } 356 break; 357 } 358 359 case kWhatPrepare: 360 { 361 mSource->prepareAsync(); 362 break; 363 } 364 365 case kWhatGetTrackInfo: 366 { 367 uint32_t replyID; 368 CHECK(msg->senderAwaitsResponse(&replyID)); 369 370 Parcel* reply; 371 CHECK(msg->findPointer("reply", (void**)&reply)); 372 373 size_t inbandTracks = 0; 374 if (mSource != NULL) { 375 inbandTracks = mSource->getTrackCount(); 376 } 377 378 // total track count 379 reply->writeInt32(inbandTracks); 380 381 // write inband tracks 382 for (size_t i = 0; i < inbandTracks; ++i) { 383 writeTrackInfo(reply, mSource->getTrackInfo(i)); 384 } 385 386 sp<AMessage> response = new AMessage; 387 response->postReply(replyID); 388 break; 389 } 390 391 case kWhatSelectTrack: 392 { 393 uint32_t replyID; 394 CHECK(msg->senderAwaitsResponse(&replyID)); 395 396 size_t trackIndex; 397 int32_t select; 398 CHECK(msg->findSize("trackIndex", &trackIndex)); 399 CHECK(msg->findInt32("select", &select)); 400 401 status_t err = INVALID_OPERATION; 402 403 size_t inbandTracks = 0; 404 if (mSource != NULL) { 405 inbandTracks = mSource->getTrackCount(); 406 } 407 408 if (trackIndex < inbandTracks) { 409 err = mSource->selectTrack(trackIndex, select); 410 } 411 412 sp<AMessage> response = new AMessage; 413 response->setInt32("err", err); 414 415 response->postReply(replyID); 416 break; 417 } 418 419 case kWhatPollDuration: 420 { 421 int32_t generation; 422 CHECK(msg->findInt32("generation", &generation)); 423 424 if (generation != mPollDurationGeneration) { 425 // stale 426 break; 427 } 428 429 int64_t durationUs; 430 if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { 431 sp<NuPlayerDriver> driver = mDriver.promote(); 432 if (driver != NULL) { 433 driver->notifyDuration(durationUs); 434 } 435 } 436 437 msg->post(1000000ll); // poll again in a second. 438 break; 439 } 440 441 case kWhatSetVideoNativeWindow: 442 { 443 ALOGV("kWhatSetVideoNativeWindow"); 444 445 mDeferredActions.push_back( 446 new ShutdownDecoderAction( 447 false /* audio */, true /* video */)); 448 449 sp<RefBase> obj; 450 CHECK(msg->findObject("native-window", &obj)); 451 452 mDeferredActions.push_back( 453 new SetSurfaceAction( 454 static_cast<NativeWindowWrapper *>(obj.get()))); 455 456 if (obj != NULL) { 457 // If there is a new surface texture, instantiate decoders 458 // again if possible. 459 mDeferredActions.push_back( 460 new SimpleAction(&NuPlayer::performScanSources)); 461 } 462 463 processDeferredActions(); 464 break; 465 } 466 467 case kWhatSetAudioSink: 468 { 469 ALOGV("kWhatSetAudioSink"); 470 471 sp<RefBase> obj; 472 CHECK(msg->findObject("sink", &obj)); 473 474 mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); 475 break; 476 } 477 478 case kWhatStart: 479 { 480 ALOGV("kWhatStart"); 481 482 mVideoIsAVC = false; 483 mAudioEOS = false; 484 mVideoEOS = false; 485 mSkipRenderingAudioUntilMediaTimeUs = -1; 486 mSkipRenderingVideoUntilMediaTimeUs = -1; 487 mVideoLateByUs = 0; 488 mNumFramesTotal = 0; 489 mNumFramesDropped = 0; 490 mStarted = true; 491 492 mSource->start(); 493 494 uint32_t flags = 0; 495 496 if (mSource->isRealTime()) { 497 flags |= Renderer::FLAG_REAL_TIME; 498 } 499 500 mRenderer = new Renderer( 501 mAudioSink, 502 new AMessage(kWhatRendererNotify, id()), 503 flags); 504 505 looper()->registerHandler(mRenderer); 506 507 postScanSources(); 508 break; 509 } 510 511 case kWhatScanSources: 512 { 513 int32_t generation; 514 CHECK(msg->findInt32("generation", &generation)); 515 if (generation != mScanSourcesGeneration) { 516 // Drop obsolete msg. 517 break; 518 } 519 520 mScanSourcesPending = false; 521 522 ALOGV("scanning sources haveAudio=%d, haveVideo=%d", 523 mAudioDecoder != NULL, mVideoDecoder != NULL); 524 525 bool mHadAnySourcesBefore = 526 (mAudioDecoder != NULL) || (mVideoDecoder != NULL); 527 528 if (mNativeWindow != NULL) { 529 instantiateDecoder(false, &mVideoDecoder); 530 } 531 532 if (mAudioSink != NULL) { 533 instantiateDecoder(true, &mAudioDecoder); 534 } 535 536 if (!mHadAnySourcesBefore 537 && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { 538 // This is the first time we've found anything playable. 539 540 if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) { 541 schedulePollDuration(); 542 } 543 } 544 545 status_t err; 546 if ((err = mSource->feedMoreTSData()) != OK) { 547 if (mAudioDecoder == NULL && mVideoDecoder == NULL) { 548 // We're not currently decoding anything (no audio or 549 // video tracks found) and we just ran out of input data. 550 551 if (err == ERROR_END_OF_STREAM) { 552 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 553 } else { 554 notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 555 } 556 } 557 break; 558 } 559 560 if ((mAudioDecoder == NULL && mAudioSink != NULL) 561 || (mVideoDecoder == NULL && mNativeWindow != NULL)) { 562 msg->post(100000ll); 563 mScanSourcesPending = true; 564 } 565 break; 566 } 567 568 case kWhatVideoNotify: 569 case kWhatAudioNotify: 570 { 571 bool audio = msg->what() == kWhatAudioNotify; 572 573 int32_t what; 574 CHECK(msg->findInt32("what", &what)); 575 576 if (what == Decoder::kWhatFillThisBuffer) { 577 status_t err = feedDecoderInputData( 578 audio, msg); 579 580 if (err == -EWOULDBLOCK) { 581 if (mSource->feedMoreTSData() == OK) { 582 msg->post(10000ll); 583 } 584 } 585 } else if (what == Decoder::kWhatEOS) { 586 int32_t err; 587 CHECK(msg->findInt32("err", &err)); 588 589 if (err == ERROR_END_OF_STREAM) { 590 ALOGV("got %s decoder EOS", audio ? "audio" : "video"); 591 } else { 592 ALOGV("got %s decoder EOS w/ error %d", 593 audio ? "audio" : "video", 594 err); 595 } 596 597 mRenderer->queueEOS(audio, err); 598 } else if (what == Decoder::kWhatFlushCompleted) { 599 bool needShutdown; 600 601 if (audio) { 602 CHECK(IsFlushingState(mFlushingAudio, &needShutdown)); 603 mFlushingAudio = FLUSHED; 604 } else { 605 CHECK(IsFlushingState(mFlushingVideo, &needShutdown)); 606 mFlushingVideo = FLUSHED; 607 608 mVideoLateByUs = 0; 609 } 610 611 ALOGV("decoder %s flush completed", audio ? "audio" : "video"); 612 613 if (needShutdown) { 614 ALOGV("initiating %s decoder shutdown", 615 audio ? "audio" : "video"); 616 617 (audio ? mAudioDecoder : mVideoDecoder)->initiateShutdown(); 618 619 if (audio) { 620 mFlushingAudio = SHUTTING_DOWN_DECODER; 621 } else { 622 mFlushingVideo = SHUTTING_DOWN_DECODER; 623 } 624 } 625 626 finishFlushIfPossible(); 627 } else if (what == Decoder::kWhatOutputFormatChanged) { 628 sp<AMessage> format; 629 CHECK(msg->findMessage("format", &format)); 630 631 if (audio) { 632 int32_t numChannels; 633 CHECK(format->findInt32( 634 "channel-count", &numChannels)); 635 636 int32_t sampleRate; 637 CHECK(format->findInt32("sample-rate", &sampleRate)); 638 639 ALOGV("Audio output format changed to %d Hz, %d channels", 640 sampleRate, numChannels); 641 642 mAudioSink->close(); 643 644 audio_output_flags_t flags; 645 int64_t durationUs; 646 // FIXME: we should handle the case where the video decoder 647 // is created after we receive the format change indication. 648 // Current code will just make that we select deep buffer 649 // with video which should not be a problem as it should 650 // not prevent from keeping A/V sync. 651 if (mVideoDecoder == NULL && 652 mSource->getDuration(&durationUs) == OK && 653 durationUs 654 > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { 655 flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; 656 } else { 657 flags = AUDIO_OUTPUT_FLAG_NONE; 658 } 659 660 int32_t channelMask; 661 if (!format->findInt32("channel-mask", &channelMask)) { 662 channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; 663 } 664 665 CHECK_EQ(mAudioSink->open( 666 sampleRate, 667 numChannels, 668 (audio_channel_mask_t)channelMask, 669 AUDIO_FORMAT_PCM_16_BIT, 670 8 /* bufferCount */, 671 NULL, 672 NULL, 673 flags), 674 (status_t)OK); 675 mAudioSink->start(); 676 677 mRenderer->signalAudioSinkChanged(); 678 } else { 679 // video 680 681 int32_t width, height; 682 CHECK(format->findInt32("width", &width)); 683 CHECK(format->findInt32("height", &height)); 684 685 int32_t cropLeft, cropTop, cropRight, cropBottom; 686 CHECK(format->findRect( 687 "crop", 688 &cropLeft, &cropTop, &cropRight, &cropBottom)); 689 690 int32_t displayWidth = cropRight - cropLeft + 1; 691 int32_t displayHeight = cropBottom - cropTop + 1; 692 693 ALOGV("Video output format changed to %d x %d " 694 "(crop: %d x %d @ (%d, %d))", 695 width, height, 696 displayWidth, 697 displayHeight, 698 cropLeft, cropTop); 699 700 sp<AMessage> videoInputFormat = 701 mSource->getFormat(false /* audio */); 702 703 // Take into account sample aspect ratio if necessary: 704 int32_t sarWidth, sarHeight; 705 if (videoInputFormat->findInt32("sar-width", &sarWidth) 706 && videoInputFormat->findInt32( 707 "sar-height", &sarHeight)) { 708 ALOGV("Sample aspect ratio %d : %d", 709 sarWidth, sarHeight); 710 711 displayWidth = (displayWidth * sarWidth) / sarHeight; 712 713 ALOGV("display dimensions %d x %d", 714 displayWidth, displayHeight); 715 } 716 717 notifyListener( 718 MEDIA_SET_VIDEO_SIZE, displayWidth, displayHeight); 719 } 720 } else if (what == Decoder::kWhatShutdownCompleted) { 721 ALOGV("%s shutdown completed", audio ? "audio" : "video"); 722 if (audio) { 723 mAudioDecoder.clear(); 724 725 CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); 726 mFlushingAudio = SHUT_DOWN; 727 } else { 728 mVideoDecoder.clear(); 729 730 CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); 731 mFlushingVideo = SHUT_DOWN; 732 } 733 734 finishFlushIfPossible(); 735 } else if (what == Decoder::kWhatError) { 736 ALOGE("Received error from %s decoder, aborting playback.", 737 audio ? "audio" : "video"); 738 739 mRenderer->queueEOS(audio, UNKNOWN_ERROR); 740 } else if (what == Decoder::kWhatDrainThisBuffer) { 741 renderBuffer(audio, msg); 742 } else { 743 ALOGV("Unhandled decoder notification %d '%c%c%c%c'.", 744 what, 745 what >> 24, 746 (what >> 16) & 0xff, 747 (what >> 8) & 0xff, 748 what & 0xff); 749 } 750 751 break; 752 } 753 754 case kWhatRendererNotify: 755 { 756 int32_t what; 757 CHECK(msg->findInt32("what", &what)); 758 759 if (what == Renderer::kWhatEOS) { 760 int32_t audio; 761 CHECK(msg->findInt32("audio", &audio)); 762 763 int32_t finalResult; 764 CHECK(msg->findInt32("finalResult", &finalResult)); 765 766 if (audio) { 767 mAudioEOS = true; 768 } else { 769 mVideoEOS = true; 770 } 771 772 if (finalResult == ERROR_END_OF_STREAM) { 773 ALOGV("reached %s EOS", audio ? "audio" : "video"); 774 } else { 775 ALOGE("%s track encountered an error (%d)", 776 audio ? "audio" : "video", finalResult); 777 778 notifyListener( 779 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult); 780 } 781 782 if ((mAudioEOS || mAudioDecoder == NULL) 783 && (mVideoEOS || mVideoDecoder == NULL)) { 784 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 785 } 786 } else if (what == Renderer::kWhatPosition) { 787 int64_t positionUs; 788 CHECK(msg->findInt64("positionUs", &positionUs)); 789 790 CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); 791 792 if (mDriver != NULL) { 793 sp<NuPlayerDriver> driver = mDriver.promote(); 794 if (driver != NULL) { 795 driver->notifyPosition(positionUs); 796 797 driver->notifyFrameStats( 798 mNumFramesTotal, mNumFramesDropped); 799 } 800 } 801 } else if (what == Renderer::kWhatFlushComplete) { 802 int32_t audio; 803 CHECK(msg->findInt32("audio", &audio)); 804 805 ALOGV("renderer %s flush completed.", audio ? "audio" : "video"); 806 } else if (what == Renderer::kWhatVideoRenderingStart) { 807 notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0); 808 } else if (what == Renderer::kWhatMediaRenderingStart) { 809 ALOGV("media rendering started"); 810 notifyListener(MEDIA_STARTED, 0, 0); 811 } 812 break; 813 } 814 815 case kWhatMoreDataQueued: 816 { 817 break; 818 } 819 820 case kWhatReset: 821 { 822 ALOGV("kWhatReset"); 823 824 mDeferredActions.push_back( 825 new ShutdownDecoderAction( 826 true /* audio */, true /* video */)); 827 828 mDeferredActions.push_back( 829 new SimpleAction(&NuPlayer::performReset)); 830 831 processDeferredActions(); 832 break; 833 } 834 835 case kWhatSeek: 836 { 837 int64_t seekTimeUs; 838 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 839 840 ALOGV("kWhatSeek seekTimeUs=%lld us", seekTimeUs); 841 842 mDeferredActions.push_back( 843 new SimpleAction(&NuPlayer::performDecoderFlush)); 844 845 mDeferredActions.push_back(new SeekAction(seekTimeUs)); 846 847 processDeferredActions(); 848 break; 849 } 850 851 case kWhatPause: 852 { 853 CHECK(mRenderer != NULL); 854 mSource->pause(); 855 mRenderer->pause(); 856 break; 857 } 858 859 case kWhatResume: 860 { 861 CHECK(mRenderer != NULL); 862 mSource->resume(); 863 mRenderer->resume(); 864 break; 865 } 866 867 case kWhatSourceNotify: 868 { 869 onSourceNotify(msg); 870 break; 871 } 872 873 default: 874 TRESPASS(); 875 break; 876 } 877} 878 879void NuPlayer::finishFlushIfPossible() { 880 if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) { 881 return; 882 } 883 884 if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) { 885 return; 886 } 887 888 ALOGV("both audio and video are flushed now."); 889 890 if (mTimeDiscontinuityPending) { 891 mRenderer->signalTimeDiscontinuity(); 892 mTimeDiscontinuityPending = false; 893 } 894 895 if (mAudioDecoder != NULL) { 896 mAudioDecoder->signalResume(); 897 } 898 899 if (mVideoDecoder != NULL) { 900 mVideoDecoder->signalResume(); 901 } 902 903 mFlushingAudio = NONE; 904 mFlushingVideo = NONE; 905 906 processDeferredActions(); 907} 908 909void NuPlayer::postScanSources() { 910 if (mScanSourcesPending) { 911 return; 912 } 913 914 sp<AMessage> msg = new AMessage(kWhatScanSources, id()); 915 msg->setInt32("generation", mScanSourcesGeneration); 916 msg->post(); 917 918 mScanSourcesPending = true; 919} 920 921status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { 922 if (*decoder != NULL) { 923 return OK; 924 } 925 926 sp<AMessage> format = mSource->getFormat(audio); 927 928 if (format == NULL) { 929 return -EWOULDBLOCK; 930 } 931 932 if (!audio) { 933 AString mime; 934 CHECK(format->findString("mime", &mime)); 935 mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str()); 936 } 937 938 sp<AMessage> notify = 939 new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify, 940 id()); 941 942 *decoder = audio ? new Decoder(notify) : 943 new Decoder(notify, mNativeWindow); 944 (*decoder)->init(); 945 (*decoder)->configure(format); 946 947 return OK; 948} 949 950status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { 951 sp<AMessage> reply; 952 CHECK(msg->findMessage("reply", &reply)); 953 954 if ((audio && IsFlushingState(mFlushingAudio)) 955 || (!audio && IsFlushingState(mFlushingVideo))) { 956 reply->setInt32("err", INFO_DISCONTINUITY); 957 reply->post(); 958 return OK; 959 } 960 961 sp<ABuffer> accessUnit; 962 963 bool dropAccessUnit; 964 do { 965 status_t err = mSource->dequeueAccessUnit(audio, &accessUnit); 966 967 if (err == -EWOULDBLOCK) { 968 return err; 969 } else if (err != OK) { 970 if (err == INFO_DISCONTINUITY) { 971 int32_t type; 972 CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); 973 974 bool formatChange = 975 (audio && 976 (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT)) 977 || (!audio && 978 (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT)); 979 980 bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0; 981 982 ALOGI("%s discontinuity (formatChange=%d, time=%d)", 983 audio ? "audio" : "video", formatChange, timeChange); 984 985 if (audio) { 986 mSkipRenderingAudioUntilMediaTimeUs = -1; 987 } else { 988 mSkipRenderingVideoUntilMediaTimeUs = -1; 989 } 990 991 if (timeChange) { 992 sp<AMessage> extra; 993 if (accessUnit->meta()->findMessage("extra", &extra) 994 && extra != NULL) { 995 int64_t resumeAtMediaTimeUs; 996 if (extra->findInt64( 997 "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { 998 ALOGI("suppressing rendering of %s until %lld us", 999 audio ? "audio" : "video", resumeAtMediaTimeUs); 1000 1001 if (audio) { 1002 mSkipRenderingAudioUntilMediaTimeUs = 1003 resumeAtMediaTimeUs; 1004 } else { 1005 mSkipRenderingVideoUntilMediaTimeUs = 1006 resumeAtMediaTimeUs; 1007 } 1008 } 1009 } 1010 } 1011 1012 mTimeDiscontinuityPending = 1013 mTimeDiscontinuityPending || timeChange; 1014 1015 if (formatChange || timeChange) { 1016 if (mFlushingAudio == NONE && mFlushingVideo == NONE) { 1017 // And we'll resume scanning sources once we're done 1018 // flushing. 1019 mDeferredActions.push_front( 1020 new SimpleAction( 1021 &NuPlayer::performScanSources)); 1022 } 1023 1024 sp<AMessage> newFormat = mSource->getFormat(audio); 1025 sp<Decoder> &decoder = audio ? mAudioDecoder : mVideoDecoder; 1026 if (formatChange && !decoder->supportsSeamlessFormatChange(newFormat)) { 1027 flushDecoder(audio, /* needShutdown = */ true); 1028 } else { 1029 flushDecoder(audio, /* needShutdown = */ false); 1030 err = OK; 1031 } 1032 } else { 1033 // This stream is unaffected by the discontinuity 1034 1035 if (audio) { 1036 mFlushingAudio = FLUSHED; 1037 } else { 1038 mFlushingVideo = FLUSHED; 1039 } 1040 1041 finishFlushIfPossible(); 1042 1043 return -EWOULDBLOCK; 1044 } 1045 } 1046 1047 reply->setInt32("err", err); 1048 reply->post(); 1049 return OK; 1050 } 1051 1052 if (!audio) { 1053 ++mNumFramesTotal; 1054 } 1055 1056 dropAccessUnit = false; 1057 if (!audio 1058 && mVideoLateByUs > 100000ll 1059 && mVideoIsAVC 1060 && !IsAVCReferenceFrame(accessUnit)) { 1061 dropAccessUnit = true; 1062 ++mNumFramesDropped; 1063 } 1064 } while (dropAccessUnit); 1065 1066 // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); 1067 1068#if 0 1069 int64_t mediaTimeUs; 1070 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); 1071 ALOGV("feeding %s input buffer at media time %.2f secs", 1072 audio ? "audio" : "video", 1073 mediaTimeUs / 1E6); 1074#endif 1075 1076 reply->setBuffer("buffer", accessUnit); 1077 reply->post(); 1078 1079 return OK; 1080} 1081 1082void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { 1083 // ALOGV("renderBuffer %s", audio ? "audio" : "video"); 1084 1085 sp<AMessage> reply; 1086 CHECK(msg->findMessage("reply", &reply)); 1087 1088 if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) { 1089 // We're currently attempting to flush the decoder, in order 1090 // to complete this, the decoder wants all its buffers back, 1091 // so we don't want any output buffers it sent us (from before 1092 // we initiated the flush) to be stuck in the renderer's queue. 1093 1094 ALOGV("we're still flushing the %s decoder, sending its output buffer" 1095 " right back.", audio ? "audio" : "video"); 1096 1097 reply->post(); 1098 return; 1099 } 1100 1101 sp<ABuffer> buffer; 1102 CHECK(msg->findBuffer("buffer", &buffer)); 1103 1104 int64_t &skipUntilMediaTimeUs = 1105 audio 1106 ? mSkipRenderingAudioUntilMediaTimeUs 1107 : mSkipRenderingVideoUntilMediaTimeUs; 1108 1109 if (skipUntilMediaTimeUs >= 0) { 1110 int64_t mediaTimeUs; 1111 CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); 1112 1113 if (mediaTimeUs < skipUntilMediaTimeUs) { 1114 ALOGV("dropping %s buffer at time %lld as requested.", 1115 audio ? "audio" : "video", 1116 mediaTimeUs); 1117 1118 reply->post(); 1119 return; 1120 } 1121 1122 skipUntilMediaTimeUs = -1; 1123 } 1124 1125 mRenderer->queueBuffer(audio, buffer, reply); 1126} 1127 1128void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) { 1129 if (mDriver == NULL) { 1130 return; 1131 } 1132 1133 sp<NuPlayerDriver> driver = mDriver.promote(); 1134 1135 if (driver == NULL) { 1136 return; 1137 } 1138 1139 driver->notifyListener(msg, ext1, ext2, in); 1140} 1141 1142void NuPlayer::flushDecoder(bool audio, bool needShutdown) { 1143 ALOGV("[%s] flushDecoder needShutdown=%d", 1144 audio ? "audio" : "video", needShutdown); 1145 1146 if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) { 1147 ALOGI("flushDecoder %s without decoder present", 1148 audio ? "audio" : "video"); 1149 } 1150 1151 // Make sure we don't continue to scan sources until we finish flushing. 1152 ++mScanSourcesGeneration; 1153 mScanSourcesPending = false; 1154 1155 (audio ? mAudioDecoder : mVideoDecoder)->signalFlush(); 1156 mRenderer->flush(audio); 1157 1158 FlushStatus newStatus = 1159 needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER; 1160 1161 if (audio) { 1162 CHECK(mFlushingAudio == NONE 1163 || mFlushingAudio == AWAITING_DISCONTINUITY); 1164 1165 mFlushingAudio = newStatus; 1166 1167 if (mFlushingVideo == NONE) { 1168 mFlushingVideo = (mVideoDecoder != NULL) 1169 ? AWAITING_DISCONTINUITY 1170 : FLUSHED; 1171 } 1172 } else { 1173 CHECK(mFlushingVideo == NONE 1174 || mFlushingVideo == AWAITING_DISCONTINUITY); 1175 1176 mFlushingVideo = newStatus; 1177 1178 if (mFlushingAudio == NONE) { 1179 mFlushingAudio = (mAudioDecoder != NULL) 1180 ? AWAITING_DISCONTINUITY 1181 : FLUSHED; 1182 } 1183 } 1184} 1185 1186sp<AMessage> NuPlayer::Source::getFormat(bool audio) { 1187 sp<MetaData> meta = getFormatMeta(audio); 1188 1189 if (meta == NULL) { 1190 return NULL; 1191 } 1192 1193 sp<AMessage> msg = new AMessage; 1194 1195 if(convertMetaDataToMessage(meta, &msg) == OK) { 1196 return msg; 1197 } 1198 return NULL; 1199} 1200 1201status_t NuPlayer::setVideoScalingMode(int32_t mode) { 1202 mVideoScalingMode = mode; 1203 if (mNativeWindow != NULL) { 1204 status_t ret = native_window_set_scaling_mode( 1205 mNativeWindow->getNativeWindow().get(), mVideoScalingMode); 1206 if (ret != OK) { 1207 ALOGE("Failed to set scaling mode (%d): %s", 1208 -ret, strerror(-ret)); 1209 return ret; 1210 } 1211 } 1212 return OK; 1213} 1214 1215status_t NuPlayer::getTrackInfo(Parcel* reply) const { 1216 sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, id()); 1217 msg->setPointer("reply", reply); 1218 1219 sp<AMessage> response; 1220 status_t err = msg->postAndAwaitResponse(&response); 1221 return err; 1222} 1223 1224status_t NuPlayer::selectTrack(size_t trackIndex, bool select) { 1225 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id()); 1226 msg->setSize("trackIndex", trackIndex); 1227 msg->setInt32("select", select); 1228 1229 sp<AMessage> response; 1230 status_t err = msg->postAndAwaitResponse(&response); 1231 1232 if (err != OK) { 1233 return err; 1234 } 1235 1236 if (!response->findInt32("err", &err)) { 1237 err = OK; 1238 } 1239 1240 return err; 1241} 1242 1243void NuPlayer::schedulePollDuration() { 1244 sp<AMessage> msg = new AMessage(kWhatPollDuration, id()); 1245 msg->setInt32("generation", mPollDurationGeneration); 1246 msg->post(); 1247} 1248 1249void NuPlayer::cancelPollDuration() { 1250 ++mPollDurationGeneration; 1251} 1252 1253void NuPlayer::processDeferredActions() { 1254 while (!mDeferredActions.empty()) { 1255 // We won't execute any deferred actions until we're no longer in 1256 // an intermediate state, i.e. one more more decoders are currently 1257 // flushing or shutting down. 1258 1259 if (mRenderer != NULL) { 1260 // There's an edge case where the renderer owns all output 1261 // buffers and is paused, therefore the decoder will not read 1262 // more input data and will never encounter the matching 1263 // discontinuity. To avoid this, we resume the renderer. 1264 1265 if (mFlushingAudio == AWAITING_DISCONTINUITY 1266 || mFlushingVideo == AWAITING_DISCONTINUITY) { 1267 mRenderer->resume(); 1268 } 1269 } 1270 1271 if (mFlushingAudio != NONE || mFlushingVideo != NONE) { 1272 // We're currently flushing, postpone the reset until that's 1273 // completed. 1274 1275 ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d", 1276 mFlushingAudio, mFlushingVideo); 1277 1278 break; 1279 } 1280 1281 sp<Action> action = *mDeferredActions.begin(); 1282 mDeferredActions.erase(mDeferredActions.begin()); 1283 1284 action->execute(this); 1285 } 1286} 1287 1288void NuPlayer::performSeek(int64_t seekTimeUs) { 1289 ALOGV("performSeek seekTimeUs=%lld us (%.2f secs)", 1290 seekTimeUs, 1291 seekTimeUs / 1E6); 1292 1293 mSource->seekTo(seekTimeUs); 1294 1295 if (mDriver != NULL) { 1296 sp<NuPlayerDriver> driver = mDriver.promote(); 1297 if (driver != NULL) { 1298 driver->notifyPosition(seekTimeUs); 1299 driver->notifySeekComplete(); 1300 } 1301 } 1302 1303 // everything's flushed, continue playback. 1304} 1305 1306void NuPlayer::performDecoderFlush() { 1307 ALOGV("performDecoderFlush"); 1308 1309 if (mAudioDecoder == NULL && mVideoDecoder == NULL) { 1310 return; 1311 } 1312 1313 mTimeDiscontinuityPending = true; 1314 1315 if (mAudioDecoder != NULL) { 1316 flushDecoder(true /* audio */, false /* needShutdown */); 1317 } 1318 1319 if (mVideoDecoder != NULL) { 1320 flushDecoder(false /* audio */, false /* needShutdown */); 1321 } 1322} 1323 1324void NuPlayer::performDecoderShutdown(bool audio, bool video) { 1325 ALOGV("performDecoderShutdown audio=%d, video=%d", audio, video); 1326 1327 if ((!audio || mAudioDecoder == NULL) 1328 && (!video || mVideoDecoder == NULL)) { 1329 return; 1330 } 1331 1332 mTimeDiscontinuityPending = true; 1333 1334 if (mFlushingAudio == NONE && (!audio || mAudioDecoder == NULL)) { 1335 mFlushingAudio = FLUSHED; 1336 } 1337 1338 if (mFlushingVideo == NONE && (!video || mVideoDecoder == NULL)) { 1339 mFlushingVideo = FLUSHED; 1340 } 1341 1342 if (audio && mAudioDecoder != NULL) { 1343 flushDecoder(true /* audio */, true /* needShutdown */); 1344 } 1345 1346 if (video && mVideoDecoder != NULL) { 1347 flushDecoder(false /* audio */, true /* needShutdown */); 1348 } 1349} 1350 1351void NuPlayer::performReset() { 1352 ALOGV("performReset"); 1353 1354 CHECK(mAudioDecoder == NULL); 1355 CHECK(mVideoDecoder == NULL); 1356 1357 cancelPollDuration(); 1358 1359 ++mScanSourcesGeneration; 1360 mScanSourcesPending = false; 1361 1362 mRenderer.clear(); 1363 1364 if (mSource != NULL) { 1365 mSource->stop(); 1366 1367 looper()->unregisterHandler(mSource->id()); 1368 1369 mSource.clear(); 1370 } 1371 1372 if (mDriver != NULL) { 1373 sp<NuPlayerDriver> driver = mDriver.promote(); 1374 if (driver != NULL) { 1375 driver->notifyResetComplete(); 1376 } 1377 } 1378 1379 mStarted = false; 1380} 1381 1382void NuPlayer::performScanSources() { 1383 ALOGV("performScanSources"); 1384 1385 if (!mStarted) { 1386 return; 1387 } 1388 1389 if (mAudioDecoder == NULL || mVideoDecoder == NULL) { 1390 postScanSources(); 1391 } 1392} 1393 1394void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) { 1395 ALOGV("performSetSurface"); 1396 1397 mNativeWindow = wrapper; 1398 1399 // XXX - ignore error from setVideoScalingMode for now 1400 setVideoScalingMode(mVideoScalingMode); 1401 1402 if (mDriver != NULL) { 1403 sp<NuPlayerDriver> driver = mDriver.promote(); 1404 if (driver != NULL) { 1405 driver->notifySetSurfaceComplete(); 1406 } 1407 } 1408} 1409 1410void NuPlayer::onSourceNotify(const sp<AMessage> &msg) { 1411 int32_t what; 1412 CHECK(msg->findInt32("what", &what)); 1413 1414 switch (what) { 1415 case Source::kWhatPrepared: 1416 { 1417 if (mSource == NULL) { 1418 // This is a stale notification from a source that was 1419 // asynchronously preparing when the client called reset(). 1420 // We handled the reset, the source is gone. 1421 break; 1422 } 1423 1424 int32_t err; 1425 CHECK(msg->findInt32("err", &err)); 1426 1427 sp<NuPlayerDriver> driver = mDriver.promote(); 1428 if (driver != NULL) { 1429 // notify duration first, so that it's definitely set when 1430 // the app received the "prepare complete" callback. 1431 int64_t durationUs; 1432 if (mSource->getDuration(&durationUs) == OK) { 1433 driver->notifyDuration(durationUs); 1434 } 1435 driver->notifyPrepareCompleted(err); 1436 } 1437 1438 break; 1439 } 1440 1441 case Source::kWhatFlagsChanged: 1442 { 1443 uint32_t flags; 1444 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 1445 1446 sp<NuPlayerDriver> driver = mDriver.promote(); 1447 if (driver != NULL) { 1448 driver->notifyFlagsChanged(flags); 1449 } 1450 1451 if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION) 1452 && (!(flags & Source::FLAG_DYNAMIC_DURATION))) { 1453 cancelPollDuration(); 1454 } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION) 1455 && (flags & Source::FLAG_DYNAMIC_DURATION) 1456 && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { 1457 schedulePollDuration(); 1458 } 1459 1460 mSourceFlags = flags; 1461 break; 1462 } 1463 1464 case Source::kWhatVideoSizeChanged: 1465 { 1466 int32_t width, height; 1467 CHECK(msg->findInt32("width", &width)); 1468 CHECK(msg->findInt32("height", &height)); 1469 1470 notifyListener(MEDIA_SET_VIDEO_SIZE, width, height); 1471 break; 1472 } 1473 1474 case Source::kWhatBufferingStart: 1475 { 1476 notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0); 1477 break; 1478 } 1479 1480 case Source::kWhatBufferingEnd: 1481 { 1482 notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0); 1483 break; 1484 } 1485 1486 case Source::kWhatSubtitleData: 1487 { 1488 sp<ABuffer> buffer; 1489 CHECK(msg->findBuffer("buffer", &buffer)); 1490 1491 sendSubtitleData(buffer, 0 /* baseIndex */); 1492 break; 1493 } 1494 1495 case Source::kWhatQueueDecoderShutdown: 1496 { 1497 int32_t audio, video; 1498 CHECK(msg->findInt32("audio", &audio)); 1499 CHECK(msg->findInt32("video", &video)); 1500 1501 sp<AMessage> reply; 1502 CHECK(msg->findMessage("reply", &reply)); 1503 1504 queueDecoderShutdown(audio, video, reply); 1505 break; 1506 } 1507 1508 default: 1509 TRESPASS(); 1510 } 1511} 1512 1513void NuPlayer::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) { 1514 int32_t trackIndex; 1515 int64_t timeUs, durationUs; 1516 CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex)); 1517 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 1518 CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); 1519 1520 Parcel in; 1521 in.writeInt32(trackIndex + baseIndex); 1522 in.writeInt64(timeUs); 1523 in.writeInt64(durationUs); 1524 in.writeInt32(buffer->size()); 1525 in.writeInt32(buffer->size()); 1526 in.write(buffer->data(), buffer->size()); 1527 1528 notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in); 1529} 1530//////////////////////////////////////////////////////////////////////////////// 1531 1532void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) { 1533 sp<AMessage> notify = dupNotify(); 1534 notify->setInt32("what", kWhatFlagsChanged); 1535 notify->setInt32("flags", flags); 1536 notify->post(); 1537} 1538 1539void NuPlayer::Source::notifyVideoSizeChanged(int32_t width, int32_t height) { 1540 sp<AMessage> notify = dupNotify(); 1541 notify->setInt32("what", kWhatVideoSizeChanged); 1542 notify->setInt32("width", width); 1543 notify->setInt32("height", height); 1544 notify->post(); 1545} 1546 1547void NuPlayer::Source::notifyPrepared(status_t err) { 1548 sp<AMessage> notify = dupNotify(); 1549 notify->setInt32("what", kWhatPrepared); 1550 notify->setInt32("err", err); 1551 notify->post(); 1552} 1553 1554void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) { 1555 TRESPASS(); 1556} 1557 1558void NuPlayer::queueDecoderShutdown( 1559 bool audio, bool video, const sp<AMessage> &reply) { 1560 ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video); 1561 1562 mDeferredActions.push_back( 1563 new ShutdownDecoderAction(audio, video)); 1564 1565 mDeferredActions.push_back( 1566 new SimpleAction(&NuPlayer::performScanSources)); 1567 1568 mDeferredActions.push_back(new PostMessageAction(reply)); 1569 1570 processDeferredActions(); 1571} 1572 1573} // namespace android 1574