NuPlayer.cpp revision d9fd6317913c74e1c955eb31978c41e70d5810bc
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 "NuPlayerDecoderPassThrough.h" 26#include "NuPlayerDriver.h" 27#include "NuPlayerRenderer.h" 28#include "NuPlayerSource.h" 29#include "RTSPSource.h" 30#include "StreamingSource.h" 31#include "GenericSource.h" 32#include "TextDescriptions.h" 33 34#include "ATSParser.h" 35 36#include <cutils/properties.h> 37 38#include <media/stagefright/foundation/hexdump.h> 39#include <media/stagefright/foundation/ABuffer.h> 40#include <media/stagefright/foundation/ADebug.h> 41#include <media/stagefright/foundation/AMessage.h> 42#include <media/stagefright/MediaBuffer.h> 43#include <media/stagefright/MediaDefs.h> 44#include <media/stagefright/MediaErrors.h> 45#include <media/stagefright/MetaData.h> 46#include <gui/IGraphicBufferProducer.h> 47 48#include "avc_utils.h" 49 50#include "ESDS.h" 51#include <media/stagefright/Utils.h> 52 53namespace android { 54 55// TODO optimize buffer size for power consumption 56// The offload read buffer size is 32 KB but 24 KB uses less power. 57const size_t NuPlayer::kAggregateBufferSizeBytes = 24 * 1024; 58 59struct NuPlayer::Action : public RefBase { 60 Action() {} 61 62 virtual void execute(NuPlayer *player) = 0; 63 64private: 65 DISALLOW_EVIL_CONSTRUCTORS(Action); 66}; 67 68struct NuPlayer::SeekAction : public Action { 69 SeekAction(int64_t seekTimeUs, bool needNotify) 70 : mSeekTimeUs(seekTimeUs), 71 mNeedNotify(needNotify) { 72 } 73 74 virtual void execute(NuPlayer *player) { 75 player->performSeek(mSeekTimeUs, mNeedNotify); 76 } 77 78private: 79 int64_t mSeekTimeUs; 80 bool mNeedNotify; 81 82 DISALLOW_EVIL_CONSTRUCTORS(SeekAction); 83}; 84 85struct NuPlayer::SetSurfaceAction : public Action { 86 SetSurfaceAction(const sp<NativeWindowWrapper> &wrapper) 87 : mWrapper(wrapper) { 88 } 89 90 virtual void execute(NuPlayer *player) { 91 player->performSetSurface(mWrapper); 92 } 93 94private: 95 sp<NativeWindowWrapper> mWrapper; 96 97 DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction); 98}; 99 100struct NuPlayer::FlushDecoderAction : public Action { 101 FlushDecoderAction(FlushCommand audio, FlushCommand video) 102 : mAudio(audio), 103 mVideo(video) { 104 } 105 106 virtual void execute(NuPlayer *player) { 107 player->performDecoderFlush(mAudio, mVideo); 108 } 109 110private: 111 FlushCommand mAudio; 112 FlushCommand mVideo; 113 114 DISALLOW_EVIL_CONSTRUCTORS(FlushDecoderAction); 115}; 116 117struct NuPlayer::PostMessageAction : public Action { 118 PostMessageAction(const sp<AMessage> &msg) 119 : mMessage(msg) { 120 } 121 122 virtual void execute(NuPlayer *) { 123 mMessage->post(); 124 } 125 126private: 127 sp<AMessage> mMessage; 128 129 DISALLOW_EVIL_CONSTRUCTORS(PostMessageAction); 130}; 131 132// Use this if there's no state necessary to save in order to execute 133// the action. 134struct NuPlayer::SimpleAction : public Action { 135 typedef void (NuPlayer::*ActionFunc)(); 136 137 SimpleAction(ActionFunc func) 138 : mFunc(func) { 139 } 140 141 virtual void execute(NuPlayer *player) { 142 (player->*mFunc)(); 143 } 144 145private: 146 ActionFunc mFunc; 147 148 DISALLOW_EVIL_CONSTRUCTORS(SimpleAction); 149}; 150 151//////////////////////////////////////////////////////////////////////////////// 152 153NuPlayer::NuPlayer() 154 : mUIDValid(false), 155 mSourceFlags(0), 156 mVideoIsAVC(false), 157 mOffloadAudio(false), 158 mAudioDecoderGeneration(0), 159 mVideoDecoderGeneration(0), 160 mRendererGeneration(0), 161 mAudioEOS(false), 162 mVideoEOS(false), 163 mScanSourcesPending(false), 164 mScanSourcesGeneration(0), 165 mPollDurationGeneration(0), 166 mTimedTextGeneration(0), 167 mTimeDiscontinuityPending(false), 168 mFlushingAudio(NONE), 169 mFlushingVideo(NONE), 170 mNumFramesTotal(0ll), 171 mNumFramesDropped(0ll), 172 mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW), 173 mStarted(false) { 174 clearFlushComplete(); 175} 176 177NuPlayer::~NuPlayer() { 178} 179 180void NuPlayer::setUID(uid_t uid) { 181 mUIDValid = true; 182 mUID = uid; 183} 184 185void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) { 186 mDriver = driver; 187} 188 189void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) { 190 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 191 192 sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); 193 194 msg->setObject("source", new StreamingSource(notify, source)); 195 msg->post(); 196} 197 198static bool IsHTTPLiveURL(const char *url) { 199 if (!strncasecmp("http://", url, 7) 200 || !strncasecmp("https://", url, 8) 201 || !strncasecmp("file://", url, 7)) { 202 size_t len = strlen(url); 203 if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) { 204 return true; 205 } 206 207 if (strstr(url,"m3u8")) { 208 return true; 209 } 210 } 211 212 return false; 213} 214 215void NuPlayer::setDataSourceAsync( 216 const sp<IMediaHTTPService> &httpService, 217 const char *url, 218 const KeyedVector<String8, String8> *headers) { 219 220 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 221 size_t len = strlen(url); 222 223 sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); 224 225 sp<Source> source; 226 if (IsHTTPLiveURL(url)) { 227 source = new HTTPLiveSource(notify, httpService, url, headers); 228 } else if (!strncasecmp(url, "rtsp://", 7)) { 229 source = new RTSPSource( 230 notify, httpService, url, headers, mUIDValid, mUID); 231 } else if ((!strncasecmp(url, "http://", 7) 232 || !strncasecmp(url, "https://", 8)) 233 && ((len >= 4 && !strcasecmp(".sdp", &url[len - 4])) 234 || strstr(url, ".sdp?"))) { 235 source = new RTSPSource( 236 notify, httpService, url, headers, mUIDValid, mUID, true); 237 } else { 238 sp<GenericSource> genericSource = 239 new GenericSource(notify, mUIDValid, mUID); 240 // Don't set FLAG_SECURE on mSourceFlags here for widevine. 241 // The correct flags will be updated in Source::kWhatFlagsChanged 242 // handler when GenericSource is prepared. 243 244 status_t err = genericSource->setDataSource(httpService, url, headers); 245 246 if (err == OK) { 247 source = genericSource; 248 } else { 249 ALOGE("Failed to set data source!"); 250 } 251 } 252 msg->setObject("source", source); 253 msg->post(); 254} 255 256void NuPlayer::setDataSourceAsync(int fd, int64_t offset, int64_t length) { 257 sp<AMessage> msg = new AMessage(kWhatSetDataSource, id()); 258 259 sp<AMessage> notify = new AMessage(kWhatSourceNotify, id()); 260 261 sp<GenericSource> source = 262 new GenericSource(notify, mUIDValid, mUID); 263 264 status_t err = source->setDataSource(fd, offset, length); 265 266 if (err != OK) { 267 ALOGE("Failed to set data source!"); 268 source = NULL; 269 } 270 271 msg->setObject("source", source); 272 msg->post(); 273} 274 275void NuPlayer::prepareAsync() { 276 (new AMessage(kWhatPrepare, id()))->post(); 277} 278 279void NuPlayer::setVideoSurfaceTextureAsync( 280 const sp<IGraphicBufferProducer> &bufferProducer) { 281 sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, id()); 282 283 if (bufferProducer == NULL) { 284 msg->setObject("native-window", NULL); 285 } else { 286 msg->setObject( 287 "native-window", 288 new NativeWindowWrapper( 289 new Surface(bufferProducer, true /* controlledByApp */))); 290 } 291 292 msg->post(); 293} 294 295void NuPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) { 296 sp<AMessage> msg = new AMessage(kWhatSetAudioSink, id()); 297 msg->setObject("sink", sink); 298 msg->post(); 299} 300 301void NuPlayer::start() { 302 (new AMessage(kWhatStart, id()))->post(); 303} 304 305void NuPlayer::pause() { 306 (new AMessage(kWhatPause, id()))->post(); 307} 308 309void NuPlayer::resetAsync() { 310 if (mSource != NULL) { 311 // During a reset, the data source might be unresponsive already, we need to 312 // disconnect explicitly so that reads exit promptly. 313 // We can't queue the disconnect request to the looper, as it might be 314 // queued behind a stuck read and never gets processed. 315 // Doing a disconnect outside the looper to allows the pending reads to exit 316 // (either successfully or with error). 317 mSource->disconnect(); 318 } 319 320 (new AMessage(kWhatReset, id()))->post(); 321} 322 323void NuPlayer::seekToAsync(int64_t seekTimeUs, bool needNotify) { 324 sp<AMessage> msg = new AMessage(kWhatSeek, id()); 325 msg->setInt64("seekTimeUs", seekTimeUs); 326 msg->setInt32("needNotify", needNotify); 327 msg->post(); 328} 329 330 331void NuPlayer::writeTrackInfo( 332 Parcel* reply, const sp<AMessage> format) const { 333 int32_t trackType; 334 CHECK(format->findInt32("type", &trackType)); 335 336 AString lang; 337 CHECK(format->findString("language", &lang)); 338 339 reply->writeInt32(2); // write something non-zero 340 reply->writeInt32(trackType); 341 reply->writeString16(String16(lang.c_str())); 342 343 if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { 344 AString mime; 345 CHECK(format->findString("mime", &mime)); 346 347 int32_t isAuto, isDefault, isForced; 348 CHECK(format->findInt32("auto", &isAuto)); 349 CHECK(format->findInt32("default", &isDefault)); 350 CHECK(format->findInt32("forced", &isForced)); 351 352 reply->writeString16(String16(mime.c_str())); 353 reply->writeInt32(isAuto); 354 reply->writeInt32(isDefault); 355 reply->writeInt32(isForced); 356 } 357} 358 359void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { 360 switch (msg->what()) { 361 case kWhatSetDataSource: 362 { 363 ALOGV("kWhatSetDataSource"); 364 365 CHECK(mSource == NULL); 366 367 status_t err = OK; 368 sp<RefBase> obj; 369 CHECK(msg->findObject("source", &obj)); 370 if (obj != NULL) { 371 mSource = static_cast<Source *>(obj.get()); 372 } else { 373 err = UNKNOWN_ERROR; 374 } 375 376 CHECK(mDriver != NULL); 377 sp<NuPlayerDriver> driver = mDriver.promote(); 378 if (driver != NULL) { 379 driver->notifySetDataSourceCompleted(err); 380 } 381 break; 382 } 383 384 case kWhatPrepare: 385 { 386 mSource->prepareAsync(); 387 break; 388 } 389 390 case kWhatGetTrackInfo: 391 { 392 uint32_t replyID; 393 CHECK(msg->senderAwaitsResponse(&replyID)); 394 395 Parcel* reply; 396 CHECK(msg->findPointer("reply", (void**)&reply)); 397 398 size_t inbandTracks = 0; 399 if (mSource != NULL) { 400 inbandTracks = mSource->getTrackCount(); 401 } 402 403 size_t ccTracks = 0; 404 if (mCCDecoder != NULL) { 405 ccTracks = mCCDecoder->getTrackCount(); 406 } 407 408 // total track count 409 reply->writeInt32(inbandTracks + ccTracks); 410 411 // write inband tracks 412 for (size_t i = 0; i < inbandTracks; ++i) { 413 writeTrackInfo(reply, mSource->getTrackInfo(i)); 414 } 415 416 // write CC track 417 for (size_t i = 0; i < ccTracks; ++i) { 418 writeTrackInfo(reply, mCCDecoder->getTrackInfo(i)); 419 } 420 421 sp<AMessage> response = new AMessage; 422 response->postReply(replyID); 423 break; 424 } 425 426 case kWhatGetSelectedTrack: 427 { 428 status_t err = INVALID_OPERATION; 429 if (mSource != NULL) { 430 err = OK; 431 432 int32_t type32; 433 CHECK(msg->findInt32("type", (int32_t*)&type32)); 434 media_track_type type = (media_track_type)type32; 435 ssize_t selectedTrack = mSource->getSelectedTrack(type); 436 437 Parcel* reply; 438 CHECK(msg->findPointer("reply", (void**)&reply)); 439 reply->writeInt32(selectedTrack); 440 } 441 442 sp<AMessage> response = new AMessage; 443 response->setInt32("err", err); 444 445 uint32_t replyID; 446 CHECK(msg->senderAwaitsResponse(&replyID)); 447 response->postReply(replyID); 448 break; 449 } 450 451 case kWhatSelectTrack: 452 { 453 uint32_t replyID; 454 CHECK(msg->senderAwaitsResponse(&replyID)); 455 456 size_t trackIndex; 457 int32_t select; 458 int64_t timeUs; 459 CHECK(msg->findSize("trackIndex", &trackIndex)); 460 CHECK(msg->findInt32("select", &select)); 461 CHECK(msg->findInt64("timeUs", &timeUs)); 462 463 status_t err = INVALID_OPERATION; 464 465 size_t inbandTracks = 0; 466 if (mSource != NULL) { 467 inbandTracks = mSource->getTrackCount(); 468 } 469 size_t ccTracks = 0; 470 if (mCCDecoder != NULL) { 471 ccTracks = mCCDecoder->getTrackCount(); 472 } 473 474 if (trackIndex < inbandTracks) { 475 err = mSource->selectTrack(trackIndex, select, timeUs); 476 477 if (!select && err == OK) { 478 int32_t type; 479 sp<AMessage> info = mSource->getTrackInfo(trackIndex); 480 if (info != NULL 481 && info->findInt32("type", &type) 482 && type == MEDIA_TRACK_TYPE_TIMEDTEXT) { 483 ++mTimedTextGeneration; 484 } 485 } 486 } else { 487 trackIndex -= inbandTracks; 488 489 if (trackIndex < ccTracks) { 490 err = mCCDecoder->selectTrack(trackIndex, select); 491 } 492 } 493 494 sp<AMessage> response = new AMessage; 495 response->setInt32("err", err); 496 497 response->postReply(replyID); 498 break; 499 } 500 501 case kWhatPollDuration: 502 { 503 int32_t generation; 504 CHECK(msg->findInt32("generation", &generation)); 505 506 if (generation != mPollDurationGeneration) { 507 // stale 508 break; 509 } 510 511 int64_t durationUs; 512 if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { 513 sp<NuPlayerDriver> driver = mDriver.promote(); 514 if (driver != NULL) { 515 driver->notifyDuration(durationUs); 516 } 517 } 518 519 msg->post(1000000ll); // poll again in a second. 520 break; 521 } 522 523 case kWhatSetVideoNativeWindow: 524 { 525 ALOGV("kWhatSetVideoNativeWindow"); 526 527 sp<RefBase> obj; 528 CHECK(msg->findObject("native-window", &obj)); 529 530 if (mSource->getFormat(false /* audio */) == NULL) { 531 performSetSurface(static_cast<NativeWindowWrapper *>(obj.get())); 532 break; 533 } 534 535 mDeferredActions.push_back( 536 new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */, 537 FLUSH_CMD_SHUTDOWN /* video */)); 538 539 mDeferredActions.push_back( 540 new SetSurfaceAction( 541 static_cast<NativeWindowWrapper *>(obj.get()))); 542 543 if (obj != NULL) { 544 if (mStarted) { 545 // Issue a seek to refresh the video screen only if started otherwise 546 // the extractor may not yet be started and will assert. 547 // If the video decoder is not set (perhaps audio only in this case) 548 // do not perform a seek as it is not needed. 549 int64_t currentPositionUs = 0; 550 if (getCurrentPosition(¤tPositionUs) == OK) { 551 mDeferredActions.push_back( 552 new SeekAction(currentPositionUs, false /* needNotify */)); 553 } 554 } 555 556 // If there is a new surface texture, instantiate decoders 557 // again if possible. 558 mDeferredActions.push_back( 559 new SimpleAction(&NuPlayer::performScanSources)); 560 } 561 562 processDeferredActions(); 563 break; 564 } 565 566 case kWhatSetAudioSink: 567 { 568 ALOGV("kWhatSetAudioSink"); 569 570 sp<RefBase> obj; 571 CHECK(msg->findObject("sink", &obj)); 572 573 mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); 574 break; 575 } 576 577 case kWhatStart: 578 { 579 ALOGV("kWhatStart"); 580 if (mStarted) { 581 onResume(); 582 } else { 583 onStart(); 584 } 585 break; 586 } 587 588 case kWhatScanSources: 589 { 590 int32_t generation; 591 CHECK(msg->findInt32("generation", &generation)); 592 if (generation != mScanSourcesGeneration) { 593 // Drop obsolete msg. 594 break; 595 } 596 597 mScanSourcesPending = false; 598 599 ALOGV("scanning sources haveAudio=%d, haveVideo=%d", 600 mAudioDecoder != NULL, mVideoDecoder != NULL); 601 602 bool mHadAnySourcesBefore = 603 (mAudioDecoder != NULL) || (mVideoDecoder != NULL); 604 605 // initialize video before audio because successful initialization of 606 // video may change deep buffer mode of audio. 607 if (mNativeWindow != NULL) { 608 instantiateDecoder(false, &mVideoDecoder); 609 } 610 611 // Don't try to re-open audio sink if there's an existing decoder. 612 if (mAudioSink != NULL && mAudioDecoder == NULL) { 613 sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */); 614 sp<AMessage> videoFormat = mSource->getFormat(false /* audio */); 615 audio_stream_type_t streamType = mAudioSink->getAudioStreamType(); 616 bool canOffload = canOffloadStream(audioMeta, (videoFormat != NULL), 617 true /* is_streaming */, streamType); 618 if (canOffload) { 619 if (!mOffloadAudio) { 620 mRenderer->signalEnableOffloadAudio(); 621 } 622 // open audio sink early under offload mode. 623 sp<AMessage> format = mSource->getFormat(true /*audio*/); 624 openAudioSink(format, true /*offloadOnly*/); 625 } 626 instantiateDecoder(true, &mAudioDecoder); 627 } 628 629 if (!mHadAnySourcesBefore 630 && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { 631 // This is the first time we've found anything playable. 632 633 if (mSourceFlags & Source::FLAG_DYNAMIC_DURATION) { 634 schedulePollDuration(); 635 } 636 } 637 638 status_t err; 639 if ((err = mSource->feedMoreTSData()) != OK) { 640 if (mAudioDecoder == NULL && mVideoDecoder == NULL) { 641 // We're not currently decoding anything (no audio or 642 // video tracks found) and we just ran out of input data. 643 644 if (err == ERROR_END_OF_STREAM) { 645 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 646 } else { 647 notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 648 } 649 } 650 break; 651 } 652 653 if ((mAudioDecoder == NULL && mAudioSink != NULL) 654 || (mVideoDecoder == NULL && mNativeWindow != NULL)) { 655 msg->post(100000ll); 656 mScanSourcesPending = true; 657 } 658 break; 659 } 660 661 case kWhatVideoNotify: 662 case kWhatAudioNotify: 663 { 664 bool audio = msg->what() == kWhatAudioNotify; 665 666 int32_t currentDecoderGeneration = 667 (audio? mAudioDecoderGeneration : mVideoDecoderGeneration); 668 int32_t requesterGeneration = currentDecoderGeneration - 1; 669 CHECK(msg->findInt32("generation", &requesterGeneration)); 670 671 if (requesterGeneration != currentDecoderGeneration) { 672 ALOGV("got message from old %s decoder, generation(%d:%d)", 673 audio ? "audio" : "video", requesterGeneration, 674 currentDecoderGeneration); 675 sp<AMessage> reply; 676 if (!(msg->findMessage("reply", &reply))) { 677 return; 678 } 679 680 reply->setInt32("err", INFO_DISCONTINUITY); 681 reply->post(); 682 return; 683 } 684 685 int32_t what; 686 CHECK(msg->findInt32("what", &what)); 687 688 if (what == Decoder::kWhatFillThisBuffer) { 689 status_t err = feedDecoderInputData( 690 audio, msg); 691 692 if (err == -EWOULDBLOCK) { 693 if (mSource->feedMoreTSData() == OK) { 694 msg->post(10 * 1000ll); 695 } 696 } 697 } else if (what == Decoder::kWhatEOS) { 698 int32_t err; 699 CHECK(msg->findInt32("err", &err)); 700 701 if (err == ERROR_END_OF_STREAM) { 702 ALOGV("got %s decoder EOS", audio ? "audio" : "video"); 703 } else { 704 ALOGV("got %s decoder EOS w/ error %d", 705 audio ? "audio" : "video", 706 err); 707 } 708 709 mRenderer->queueEOS(audio, err); 710 } else if (what == Decoder::kWhatFlushCompleted) { 711 ALOGV("decoder %s flush completed", audio ? "audio" : "video"); 712 713 handleFlushComplete(audio, true /* isDecoder */); 714 finishFlushIfPossible(); 715 } else if (what == Decoder::kWhatVideoSizeChanged) { 716 sp<AMessage> format; 717 CHECK(msg->findMessage("format", &format)); 718 719 sp<AMessage> inputFormat = 720 mSource->getFormat(false /* audio */); 721 722 updateVideoSize(inputFormat, format); 723 } else if (what == Decoder::kWhatShutdownCompleted) { 724 ALOGV("%s shutdown completed", audio ? "audio" : "video"); 725 if (audio) { 726 mAudioDecoder.clear(); 727 ++mAudioDecoderGeneration; 728 729 CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER); 730 mFlushingAudio = SHUT_DOWN; 731 } else { 732 mVideoDecoder.clear(); 733 ++mVideoDecoderGeneration; 734 735 CHECK_EQ((int)mFlushingVideo, (int)SHUTTING_DOWN_DECODER); 736 mFlushingVideo = SHUT_DOWN; 737 } 738 739 finishFlushIfPossible(); 740 } else if (what == Decoder::kWhatError) { 741 status_t err; 742 if (!msg->findInt32("err", &err) || err == OK) { 743 err = UNKNOWN_ERROR; 744 } 745 746 // Decoder errors can be due to Source (e.g. from streaming), 747 // or from decoding corrupted bitstreams, or from other decoder 748 // MediaCodec operations (e.g. from an ongoing reset or seek). 749 // 750 // We try to gracefully shut down the affected decoder if possible, 751 // rather than trying to force the shutdown with something 752 // similar to performReset(). This method can lead to a hang 753 // if MediaCodec functions block after an error, but they should 754 // typically return INVALID_OPERATION instead of blocking. 755 756 FlushStatus *flushing = audio ? &mFlushingAudio : &mFlushingVideo; 757 ALOGE("received error(%#x) from %s decoder, flushing(%d), now shutting down", 758 err, audio ? "audio" : "video", *flushing); 759 760 switch (*flushing) { 761 case NONE: 762 mDeferredActions.push_back( 763 new FlushDecoderAction( 764 audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE, 765 audio ? FLUSH_CMD_NONE : FLUSH_CMD_SHUTDOWN)); 766 processDeferredActions(); 767 break; 768 case FLUSHING_DECODER: 769 *flushing = FLUSHING_DECODER_SHUTDOWN; // initiate shutdown after flush. 770 break; // Wait for flush to complete. 771 case FLUSHING_DECODER_SHUTDOWN: 772 break; // Wait for flush to complete. 773 case SHUTTING_DOWN_DECODER: 774 break; // Wait for shutdown to complete. 775 case FLUSHED: 776 // Widevine source reads must stop before releasing the video decoder. 777 if (!audio && mSource != NULL && mSourceFlags & Source::FLAG_SECURE) { 778 mSource->stop(); 779 } 780 getDecoder(audio)->initiateShutdown(); // In the middle of a seek. 781 *flushing = SHUTTING_DOWN_DECODER; // Shut down. 782 break; 783 case SHUT_DOWN: 784 finishFlushIfPossible(); // Should not occur. 785 break; // Finish anyways. 786 } 787 notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 788 } else if (what == Decoder::kWhatRenderBufferTime) { 789 renderBuffer(audio, msg); 790 } else { 791 ALOGV("Unhandled decoder notification %d '%c%c%c%c'.", 792 what, 793 what >> 24, 794 (what >> 16) & 0xff, 795 (what >> 8) & 0xff, 796 what & 0xff); 797 } 798 799 break; 800 } 801 802 case kWhatRendererNotify: 803 { 804 int32_t requesterGeneration = mRendererGeneration - 1; 805 CHECK(msg->findInt32("generation", &requesterGeneration)); 806 if (requesterGeneration != mRendererGeneration) { 807 ALOGV("got message from old renderer, generation(%d:%d)", 808 requesterGeneration, mRendererGeneration); 809 return; 810 } 811 812 int32_t what; 813 CHECK(msg->findInt32("what", &what)); 814 815 if (what == Renderer::kWhatEOS) { 816 int32_t audio; 817 CHECK(msg->findInt32("audio", &audio)); 818 819 int32_t finalResult; 820 CHECK(msg->findInt32("finalResult", &finalResult)); 821 822 if (audio) { 823 mAudioEOS = true; 824 } else { 825 mVideoEOS = true; 826 } 827 828 if (finalResult == ERROR_END_OF_STREAM) { 829 ALOGV("reached %s EOS", audio ? "audio" : "video"); 830 } else { 831 ALOGE("%s track encountered an error (%d)", 832 audio ? "audio" : "video", finalResult); 833 834 notifyListener( 835 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult); 836 } 837 838 if ((mAudioEOS || mAudioDecoder == NULL) 839 && (mVideoEOS || mVideoDecoder == NULL)) { 840 notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); 841 } 842 } else if (what == Renderer::kWhatFlushComplete) { 843 int32_t audio; 844 CHECK(msg->findInt32("audio", &audio)); 845 846 ALOGV("renderer %s flush completed.", audio ? "audio" : "video"); 847 handleFlushComplete(audio, false /* isDecoder */); 848 finishFlushIfPossible(); 849 } else if (what == Renderer::kWhatVideoRenderingStart) { 850 notifyListener(MEDIA_INFO, MEDIA_INFO_RENDERING_START, 0); 851 } else if (what == Renderer::kWhatMediaRenderingStart) { 852 ALOGV("media rendering started"); 853 notifyListener(MEDIA_STARTED, 0, 0); 854 } else if (what == Renderer::kWhatAudioOffloadTearDown) { 855 ALOGV("Tear down audio offload, fall back to s/w path if due to error."); 856 int64_t positionUs; 857 CHECK(msg->findInt64("positionUs", &positionUs)); 858 int32_t reason; 859 CHECK(msg->findInt32("reason", &reason)); 860 closeAudioSink(); 861 mAudioDecoder.clear(); 862 ++mAudioDecoderGeneration; 863 mRenderer->flush(true /* audio */); 864 if (mVideoDecoder != NULL) { 865 mRenderer->flush(false /* audio */); 866 } 867 868 performSeek(positionUs, false /* needNotify */); 869 if (reason == Renderer::kDueToError) { 870 mRenderer->signalDisableOffloadAudio(); 871 mOffloadAudio = false; 872 instantiateDecoder(true /* audio */, &mAudioDecoder); 873 } 874 } 875 break; 876 } 877 878 case kWhatMoreDataQueued: 879 { 880 break; 881 } 882 883 case kWhatReset: 884 { 885 ALOGV("kWhatReset"); 886 887 mDeferredActions.push_back( 888 new FlushDecoderAction( 889 FLUSH_CMD_SHUTDOWN /* audio */, 890 FLUSH_CMD_SHUTDOWN /* video */)); 891 892 mDeferredActions.push_back( 893 new SimpleAction(&NuPlayer::performReset)); 894 895 processDeferredActions(); 896 break; 897 } 898 899 case kWhatSeek: 900 { 901 int64_t seekTimeUs; 902 int32_t needNotify; 903 CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); 904 CHECK(msg->findInt32("needNotify", &needNotify)); 905 906 ALOGV("kWhatSeek seekTimeUs=%lld us, needNotify=%d", 907 seekTimeUs, needNotify); 908 909 mDeferredActions.push_back( 910 new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */, 911 FLUSH_CMD_FLUSH /* video */)); 912 913 mDeferredActions.push_back( 914 new SeekAction(seekTimeUs, needNotify)); 915 916 processDeferredActions(); 917 break; 918 } 919 920 case kWhatPause: 921 { 922 if (mSource != NULL) { 923 mSource->pause(); 924 } else { 925 ALOGW("pause called when source is gone or not set"); 926 } 927 if (mRenderer != NULL) { 928 mRenderer->pause(); 929 } else { 930 ALOGW("pause called when renderer is gone or not set"); 931 } 932 break; 933 } 934 935 case kWhatSourceNotify: 936 { 937 onSourceNotify(msg); 938 break; 939 } 940 941 case kWhatClosedCaptionNotify: 942 { 943 onClosedCaptionNotify(msg); 944 break; 945 } 946 947 default: 948 TRESPASS(); 949 break; 950 } 951} 952 953void NuPlayer::onResume() { 954 if (mSource != NULL) { 955 mSource->resume(); 956 } else { 957 ALOGW("resume called when source is gone or not set"); 958 } 959 // |mAudioDecoder| may have been released due to the pause timeout, so re-create it if 960 // needed. 961 if (audioDecoderStillNeeded() && mAudioDecoder == NULL) { 962 instantiateDecoder(true /* audio */, &mAudioDecoder); 963 } 964 if (mRenderer != NULL) { 965 mRenderer->resume(); 966 } else { 967 ALOGW("resume called when renderer is gone or not set"); 968 } 969} 970 971void NuPlayer::onStart() { 972 mVideoIsAVC = false; 973 mOffloadAudio = false; 974 mAudioEOS = false; 975 mVideoEOS = false; 976 mNumFramesTotal = 0; 977 mNumFramesDropped = 0; 978 mStarted = true; 979 980 /* instantiate decoders now for secure playback */ 981 if (mSourceFlags & Source::FLAG_SECURE) { 982 if (mNativeWindow != NULL) { 983 instantiateDecoder(false, &mVideoDecoder); 984 } 985 986 if (mAudioSink != NULL) { 987 instantiateDecoder(true, &mAudioDecoder); 988 } 989 } 990 991 mSource->start(); 992 993 uint32_t flags = 0; 994 995 if (mSource->isRealTime()) { 996 flags |= Renderer::FLAG_REAL_TIME; 997 } 998 999 sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */); 1000 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC; 1001 if (mAudioSink != NULL) { 1002 streamType = mAudioSink->getAudioStreamType(); 1003 } 1004 1005 sp<AMessage> videoFormat = mSource->getFormat(false /* audio */); 1006 1007 mOffloadAudio = 1008 canOffloadStream(audioMeta, (videoFormat != NULL), 1009 true /* is_streaming */, streamType); 1010 if (mOffloadAudio) { 1011 flags |= Renderer::FLAG_OFFLOAD_AUDIO; 1012 } 1013 1014 sp<AMessage> notify = new AMessage(kWhatRendererNotify, id()); 1015 ++mRendererGeneration; 1016 notify->setInt32("generation", mRendererGeneration); 1017 mRenderer = new Renderer(mAudioSink, notify, flags); 1018 1019 mRendererLooper = new ALooper; 1020 mRendererLooper->setName("NuPlayerRenderer"); 1021 mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO); 1022 mRendererLooper->registerHandler(mRenderer); 1023 1024 sp<MetaData> meta = getFileMeta(); 1025 int32_t rate; 1026 if (meta != NULL 1027 && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) { 1028 mRenderer->setVideoFrameRate(rate); 1029 } 1030 1031 if (mVideoDecoder != NULL) { 1032 mVideoDecoder->setRenderer(mRenderer); 1033 } 1034 if (mAudioDecoder != NULL) { 1035 mAudioDecoder->setRenderer(mRenderer); 1036 } 1037 1038 postScanSources(); 1039} 1040 1041bool NuPlayer::audioDecoderStillNeeded() { 1042 // Audio decoder is no longer needed if it's in shut/shutting down status. 1043 return ((mFlushingAudio != SHUT_DOWN) && (mFlushingAudio != SHUTTING_DOWN_DECODER)); 1044} 1045 1046void NuPlayer::handleFlushComplete(bool audio, bool isDecoder) { 1047 // We wait for both the decoder flush and the renderer flush to complete 1048 // before entering either the FLUSHED or the SHUTTING_DOWN_DECODER state. 1049 1050 mFlushComplete[audio][isDecoder] = true; 1051 if (!mFlushComplete[audio][!isDecoder]) { 1052 return; 1053 } 1054 1055 FlushStatus *state = audio ? &mFlushingAudio : &mFlushingVideo; 1056 switch (*state) { 1057 case FLUSHING_DECODER: 1058 { 1059 *state = FLUSHED; 1060 break; 1061 } 1062 1063 case FLUSHING_DECODER_SHUTDOWN: 1064 { 1065 *state = SHUTTING_DOWN_DECODER; 1066 1067 ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video"); 1068 if (!audio) { 1069 // Widevine source reads must stop before releasing the video decoder. 1070 if (mSource != NULL && mSourceFlags & Source::FLAG_SECURE) { 1071 mSource->stop(); 1072 } 1073 } 1074 getDecoder(audio)->initiateShutdown(); 1075 break; 1076 } 1077 1078 default: 1079 // decoder flush completes only occur in a flushing state. 1080 LOG_ALWAYS_FATAL_IF(isDecoder, "decoder flush in invalid state %d", *state); 1081 break; 1082 } 1083} 1084 1085void NuPlayer::finishFlushIfPossible() { 1086 if (mFlushingAudio != NONE && mFlushingAudio != FLUSHED 1087 && mFlushingAudio != SHUT_DOWN) { 1088 return; 1089 } 1090 1091 if (mFlushingVideo != NONE && mFlushingVideo != FLUSHED 1092 && mFlushingVideo != SHUT_DOWN) { 1093 return; 1094 } 1095 1096 ALOGV("both audio and video are flushed now."); 1097 1098 mPendingAudioAccessUnit.clear(); 1099 mAggregateBuffer.clear(); 1100 1101 if (mTimeDiscontinuityPending) { 1102 mRenderer->signalTimeDiscontinuity(); 1103 mTimeDiscontinuityPending = false; 1104 } 1105 1106 if (mAudioDecoder != NULL && mFlushingAudio == FLUSHED) { 1107 mAudioDecoder->signalResume(); 1108 } 1109 1110 if (mVideoDecoder != NULL && mFlushingVideo == FLUSHED) { 1111 mVideoDecoder->signalResume(); 1112 } 1113 1114 mFlushingAudio = NONE; 1115 mFlushingVideo = NONE; 1116 1117 clearFlushComplete(); 1118 1119 processDeferredActions(); 1120} 1121 1122void NuPlayer::postScanSources() { 1123 if (mScanSourcesPending) { 1124 return; 1125 } 1126 1127 sp<AMessage> msg = new AMessage(kWhatScanSources, id()); 1128 msg->setInt32("generation", mScanSourcesGeneration); 1129 msg->post(); 1130 1131 mScanSourcesPending = true; 1132} 1133 1134void NuPlayer::openAudioSink(const sp<AMessage> &format, bool offloadOnly) { 1135 uint32_t flags; 1136 int64_t durationUs; 1137 bool hasVideo = (mVideoDecoder != NULL); 1138 // FIXME: we should handle the case where the video decoder 1139 // is created after we receive the format change indication. 1140 // Current code will just make that we select deep buffer 1141 // with video which should not be a problem as it should 1142 // not prevent from keeping A/V sync. 1143 if (!hasVideo && 1144 mSource->getDuration(&durationUs) == OK && 1145 durationUs 1146 > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { 1147 flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; 1148 } else { 1149 flags = AUDIO_OUTPUT_FLAG_NONE; 1150 } 1151 1152 mOffloadAudio = mRenderer->openAudioSink( 1153 format, offloadOnly, hasVideo, flags); 1154 1155 if (mOffloadAudio) { 1156 sp<MetaData> audioMeta = 1157 mSource->getFormatMeta(true /* audio */); 1158 sendMetaDataToHal(mAudioSink, audioMeta); 1159 } 1160} 1161 1162void NuPlayer::closeAudioSink() { 1163 mRenderer->closeAudioSink(); 1164} 1165 1166status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) { 1167 if (*decoder != NULL) { 1168 return OK; 1169 } 1170 1171 sp<AMessage> format = mSource->getFormat(audio); 1172 1173 if (format == NULL) { 1174 return -EWOULDBLOCK; 1175 } 1176 1177 if (!audio) { 1178 AString mime; 1179 CHECK(format->findString("mime", &mime)); 1180 mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str()); 1181 1182 sp<AMessage> ccNotify = new AMessage(kWhatClosedCaptionNotify, id()); 1183 mCCDecoder = new CCDecoder(ccNotify); 1184 1185 if (mSourceFlags & Source::FLAG_SECURE) { 1186 format->setInt32("secure", true); 1187 } 1188 } 1189 1190 if (audio) { 1191 sp<AMessage> notify = new AMessage(kWhatAudioNotify, id()); 1192 ++mAudioDecoderGeneration; 1193 notify->setInt32("generation", mAudioDecoderGeneration); 1194 1195 if (mOffloadAudio) { 1196 *decoder = new DecoderPassThrough(notify, mSource, mRenderer); 1197 } else { 1198 *decoder = new Decoder(notify, mSource, mRenderer); 1199 } 1200 } else { 1201 sp<AMessage> notify = new AMessage(kWhatVideoNotify, id()); 1202 ++mVideoDecoderGeneration; 1203 notify->setInt32("generation", mVideoDecoderGeneration); 1204 1205 *decoder = new Decoder(notify, mSource, mRenderer, mNativeWindow); 1206 1207 // enable FRC if high-quality AV sync is requested, even if not 1208 // queuing to native window, as this will even improve textureview 1209 // playback. 1210 { 1211 char value[PROPERTY_VALUE_MAX]; 1212 if (property_get("persist.sys.media.avsync", value, NULL) && 1213 (!strcmp("1", value) || !strcasecmp("true", value))) { 1214 format->setInt32("auto-frc", 1); 1215 } 1216 } 1217 } 1218 (*decoder)->init(); 1219 (*decoder)->configure(format); 1220 1221 // allocate buffers to decrypt widevine source buffers 1222 if (!audio && (mSourceFlags & Source::FLAG_SECURE)) { 1223 Vector<sp<ABuffer> > inputBufs; 1224 CHECK_EQ((*decoder)->getInputBuffers(&inputBufs), (status_t)OK); 1225 1226 Vector<MediaBuffer *> mediaBufs; 1227 for (size_t i = 0; i < inputBufs.size(); i++) { 1228 const sp<ABuffer> &buffer = inputBufs[i]; 1229 MediaBuffer *mbuf = new MediaBuffer(buffer->data(), buffer->size()); 1230 mediaBufs.push(mbuf); 1231 } 1232 1233 status_t err = mSource->setBuffers(audio, mediaBufs); 1234 if (err != OK) { 1235 for (size_t i = 0; i < mediaBufs.size(); ++i) { 1236 mediaBufs[i]->release(); 1237 } 1238 mediaBufs.clear(); 1239 ALOGE("Secure source didn't support secure mediaBufs."); 1240 return err; 1241 } 1242 } 1243 return OK; 1244} 1245 1246status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { 1247 sp<AMessage> reply; 1248 CHECK(msg->findMessage("reply", &reply)); 1249 1250 if ((audio && mFlushingAudio != NONE) 1251 || (!audio && mFlushingVideo != NONE) 1252 || mSource == NULL) { 1253 reply->setInt32("err", INFO_DISCONTINUITY); 1254 reply->post(); 1255 return OK; 1256 } 1257 1258 sp<ABuffer> accessUnit; 1259 1260 // Aggregate smaller buffers into a larger buffer. 1261 // The goal is to reduce power consumption. 1262 // Note this will not work if the decoder requires one frame per buffer. 1263 bool doBufferAggregation = (audio && mOffloadAudio); 1264 bool needMoreData = false; 1265 1266 bool dropAccessUnit; 1267 do { 1268 status_t err; 1269 // Did we save an accessUnit earlier because of a discontinuity? 1270 if (audio && (mPendingAudioAccessUnit != NULL)) { 1271 accessUnit = mPendingAudioAccessUnit; 1272 mPendingAudioAccessUnit.clear(); 1273 err = mPendingAudioErr; 1274 ALOGV("feedDecoderInputData() use mPendingAudioAccessUnit"); 1275 } else { 1276 err = mSource->dequeueAccessUnit(audio, &accessUnit); 1277 } 1278 1279 if (err == -EWOULDBLOCK) { 1280 return err; 1281 } else if (err != OK) { 1282 if (err == INFO_DISCONTINUITY) { 1283 if (doBufferAggregation && (mAggregateBuffer != NULL)) { 1284 // We already have some data so save this for later. 1285 mPendingAudioErr = err; 1286 mPendingAudioAccessUnit = accessUnit; 1287 accessUnit.clear(); 1288 ALOGD("feedDecoderInputData() save discontinuity for later"); 1289 break; 1290 } 1291 int32_t type; 1292 CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); 1293 1294 bool formatChange = 1295 (audio && 1296 (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT)) 1297 || (!audio && 1298 (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT)); 1299 1300 bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0; 1301 1302 ALOGI("%s discontinuity (formatChange=%d, time=%d)", 1303 audio ? "audio" : "video", formatChange, timeChange); 1304 1305 mTimeDiscontinuityPending = 1306 mTimeDiscontinuityPending || timeChange; 1307 1308 bool seamlessFormatChange = false; 1309 sp<AMessage> newFormat = mSource->getFormat(audio); 1310 if (formatChange) { 1311 seamlessFormatChange = 1312 getDecoder(audio)->supportsSeamlessFormatChange(newFormat); 1313 // treat seamless format change separately 1314 formatChange = !seamlessFormatChange; 1315 } 1316 bool shutdownOrFlush = formatChange || timeChange; 1317 1318 // We want to queue up scan-sources only once per discontinuity. 1319 // We control this by doing it only if neither audio nor video are 1320 // flushing or shutting down. (After handling 1st discontinuity, one 1321 // of the flushing states will not be NONE.) 1322 // No need to scan sources if this discontinuity does not result 1323 // in a flush or shutdown, as the flushing state will stay NONE. 1324 if (mFlushingAudio == NONE && mFlushingVideo == NONE && 1325 shutdownOrFlush) { 1326 // And we'll resume scanning sources once we're done 1327 // flushing. 1328 mDeferredActions.push_front( 1329 new SimpleAction( 1330 &NuPlayer::performScanSources)); 1331 } 1332 1333 if (formatChange /* not seamless */) { 1334 // must change decoder 1335 flushDecoder(audio, /* needShutdown = */ true); 1336 } else if (timeChange) { 1337 // need to flush 1338 flushDecoder(audio, /* needShutdown = */ false, newFormat); 1339 err = OK; 1340 } else if (seamlessFormatChange) { 1341 // reuse existing decoder and don't flush 1342 updateDecoderFormatWithoutFlush(audio, newFormat); 1343 err = OK; 1344 } else { 1345 // This stream is unaffected by the discontinuity 1346 return -EWOULDBLOCK; 1347 } 1348 } 1349 1350 reply->setInt32("err", err); 1351 reply->post(); 1352 return OK; 1353 } 1354 1355 if (!audio) { 1356 ++mNumFramesTotal; 1357 } 1358 1359 dropAccessUnit = false; 1360 if (!audio 1361 && !(mSourceFlags & Source::FLAG_SECURE) 1362 && mRenderer->getVideoLateByUs() > 100000ll 1363 && mVideoIsAVC 1364 && !IsAVCReferenceFrame(accessUnit)) { 1365 dropAccessUnit = true; 1366 ++mNumFramesDropped; 1367 } 1368 1369 size_t smallSize = accessUnit->size(); 1370 needMoreData = false; 1371 if (doBufferAggregation && (mAggregateBuffer == NULL) 1372 // Don't bother if only room for a few small buffers. 1373 && (smallSize < (kAggregateBufferSizeBytes / 3))) { 1374 // Create a larger buffer for combining smaller buffers from the extractor. 1375 mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes); 1376 mAggregateBuffer->setRange(0, 0); // start empty 1377 } 1378 1379 if (doBufferAggregation && (mAggregateBuffer != NULL)) { 1380 int64_t timeUs; 1381 int64_t dummy; 1382 bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs); 1383 bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy); 1384 // Will the smaller buffer fit? 1385 size_t bigSize = mAggregateBuffer->size(); 1386 size_t roomLeft = mAggregateBuffer->capacity() - bigSize; 1387 // Should we save this small buffer for the next big buffer? 1388 // If the first small buffer did not have a timestamp then save 1389 // any buffer that does have a timestamp until the next big buffer. 1390 if ((smallSize > roomLeft) 1391 || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) { 1392 mPendingAudioErr = err; 1393 mPendingAudioAccessUnit = accessUnit; 1394 accessUnit.clear(); 1395 } else { 1396 // Grab time from first small buffer if available. 1397 if ((bigSize == 0) && smallTimestampValid) { 1398 mAggregateBuffer->meta()->setInt64("timeUs", timeUs); 1399 } 1400 // Append small buffer to the bigger buffer. 1401 memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize); 1402 bigSize += smallSize; 1403 mAggregateBuffer->setRange(0, bigSize); 1404 1405 // Keep looping until we run out of room in the mAggregateBuffer. 1406 needMoreData = true; 1407 1408 ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu", 1409 smallSize, bigSize, mAggregateBuffer->capacity()); 1410 } 1411 } 1412 } while (dropAccessUnit || needMoreData); 1413 1414 // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); 1415 1416#if 0 1417 int64_t mediaTimeUs; 1418 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); 1419 ALOGV("feeding %s input buffer at media time %.2f secs", 1420 audio ? "audio" : "video", 1421 mediaTimeUs / 1E6); 1422#endif 1423 1424 if (!audio) { 1425 mCCDecoder->decode(accessUnit); 1426 } 1427 1428 if (doBufferAggregation && (mAggregateBuffer != NULL)) { 1429 ALOGV("feedDecoderInputData() reply with aggregated buffer, %zu", 1430 mAggregateBuffer->size()); 1431 reply->setBuffer("buffer", mAggregateBuffer); 1432 mAggregateBuffer.clear(); 1433 } else { 1434 reply->setBuffer("buffer", accessUnit); 1435 } 1436 1437 reply->post(); 1438 1439 return OK; 1440} 1441 1442void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { 1443 // ALOGV("renderBuffer %s", audio ? "audio" : "video"); 1444 1445 if ((audio && mFlushingAudio != NONE) 1446 || (!audio && mFlushingVideo != NONE)) { 1447 // We're currently attempting to flush the decoder, in order 1448 // to complete this, the decoder wants all its buffers back, 1449 // so we don't want any output buffers it sent us (from before 1450 // we initiated the flush) to be stuck in the renderer's queue. 1451 1452 ALOGV("we're still flushing the %s decoder, sending its output buffer" 1453 " right back.", audio ? "audio" : "video"); 1454 1455 return; 1456 } 1457 1458 int64_t mediaTimeUs; 1459 CHECK(msg->findInt64("timeUs", &mediaTimeUs)); 1460 1461 if (!audio && mCCDecoder->isSelected()) { 1462 mCCDecoder->display(mediaTimeUs); 1463 } 1464} 1465 1466void NuPlayer::updateVideoSize( 1467 const sp<AMessage> &inputFormat, 1468 const sp<AMessage> &outputFormat) { 1469 if (inputFormat == NULL) { 1470 ALOGW("Unknown video size, reporting 0x0!"); 1471 notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0); 1472 return; 1473 } 1474 1475 int32_t displayWidth, displayHeight; 1476 int32_t cropLeft, cropTop, cropRight, cropBottom; 1477 1478 if (outputFormat != NULL) { 1479 int32_t width, height; 1480 CHECK(outputFormat->findInt32("width", &width)); 1481 CHECK(outputFormat->findInt32("height", &height)); 1482 1483 int32_t cropLeft, cropTop, cropRight, cropBottom; 1484 CHECK(outputFormat->findRect( 1485 "crop", 1486 &cropLeft, &cropTop, &cropRight, &cropBottom)); 1487 1488 displayWidth = cropRight - cropLeft + 1; 1489 displayHeight = cropBottom - cropTop + 1; 1490 1491 ALOGV("Video output format changed to %d x %d " 1492 "(crop: %d x %d @ (%d, %d))", 1493 width, height, 1494 displayWidth, 1495 displayHeight, 1496 cropLeft, cropTop); 1497 } else { 1498 CHECK(inputFormat->findInt32("width", &displayWidth)); 1499 CHECK(inputFormat->findInt32("height", &displayHeight)); 1500 1501 ALOGV("Video input format %d x %d", displayWidth, displayHeight); 1502 } 1503 1504 // Take into account sample aspect ratio if necessary: 1505 int32_t sarWidth, sarHeight; 1506 if (inputFormat->findInt32("sar-width", &sarWidth) 1507 && inputFormat->findInt32("sar-height", &sarHeight)) { 1508 ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight); 1509 1510 displayWidth = (displayWidth * sarWidth) / sarHeight; 1511 1512 ALOGV("display dimensions %d x %d", displayWidth, displayHeight); 1513 } 1514 1515 int32_t rotationDegrees; 1516 if (!inputFormat->findInt32("rotation-degrees", &rotationDegrees)) { 1517 rotationDegrees = 0; 1518 } 1519 1520 if (rotationDegrees == 90 || rotationDegrees == 270) { 1521 int32_t tmp = displayWidth; 1522 displayWidth = displayHeight; 1523 displayHeight = tmp; 1524 } 1525 1526 notifyListener( 1527 MEDIA_SET_VIDEO_SIZE, 1528 displayWidth, 1529 displayHeight); 1530} 1531 1532void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) { 1533 if (mDriver == NULL) { 1534 return; 1535 } 1536 1537 sp<NuPlayerDriver> driver = mDriver.promote(); 1538 1539 if (driver == NULL) { 1540 return; 1541 } 1542 1543 driver->notifyListener(msg, ext1, ext2, in); 1544} 1545 1546void NuPlayer::flushDecoder( 1547 bool audio, bool needShutdown, const sp<AMessage> &newFormat) { 1548 ALOGV("[%s] flushDecoder needShutdown=%d", 1549 audio ? "audio" : "video", needShutdown); 1550 1551 const sp<Decoder> &decoder = getDecoder(audio); 1552 if (decoder == NULL) { 1553 ALOGI("flushDecoder %s without decoder present", 1554 audio ? "audio" : "video"); 1555 return; 1556 } 1557 1558 // Make sure we don't continue to scan sources until we finish flushing. 1559 ++mScanSourcesGeneration; 1560 mScanSourcesPending = false; 1561 1562 decoder->signalFlush(newFormat); 1563 1564 FlushStatus newStatus = 1565 needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER; 1566 1567 mFlushComplete[audio][false /* isDecoder */] = false; 1568 mFlushComplete[audio][true /* isDecoder */] = false; 1569 if (audio) { 1570 ALOGE_IF(mFlushingAudio != NONE, 1571 "audio flushDecoder() is called in state %d", mFlushingAudio); 1572 mFlushingAudio = newStatus; 1573 } else { 1574 ALOGE_IF(mFlushingVideo != NONE, 1575 "video flushDecoder() is called in state %d", mFlushingVideo); 1576 mFlushingVideo = newStatus; 1577 1578 if (mCCDecoder != NULL) { 1579 mCCDecoder->flush(); 1580 } 1581 } 1582} 1583 1584void NuPlayer::updateDecoderFormatWithoutFlush( 1585 bool audio, const sp<AMessage> &format) { 1586 ALOGV("[%s] updateDecoderFormatWithoutFlush", audio ? "audio" : "video"); 1587 1588 const sp<Decoder> &decoder = getDecoder(audio); 1589 if (decoder == NULL) { 1590 ALOGI("updateDecoderFormatWithoutFlush %s without decoder present", 1591 audio ? "audio" : "video"); 1592 return; 1593 } 1594 1595 decoder->signalUpdateFormat(format); 1596} 1597 1598void NuPlayer::queueDecoderShutdown( 1599 bool audio, bool video, const sp<AMessage> &reply) { 1600 ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video); 1601 1602 mDeferredActions.push_back( 1603 new FlushDecoderAction( 1604 audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE, 1605 video ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE)); 1606 1607 mDeferredActions.push_back( 1608 new SimpleAction(&NuPlayer::performScanSources)); 1609 1610 mDeferredActions.push_back(new PostMessageAction(reply)); 1611 1612 processDeferredActions(); 1613} 1614 1615status_t NuPlayer::setVideoScalingMode(int32_t mode) { 1616 mVideoScalingMode = mode; 1617 if (mNativeWindow != NULL) { 1618 status_t ret = native_window_set_scaling_mode( 1619 mNativeWindow->getNativeWindow().get(), mVideoScalingMode); 1620 if (ret != OK) { 1621 ALOGE("Failed to set scaling mode (%d): %s", 1622 -ret, strerror(-ret)); 1623 return ret; 1624 } 1625 } 1626 return OK; 1627} 1628 1629status_t NuPlayer::getTrackInfo(Parcel* reply) const { 1630 sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, id()); 1631 msg->setPointer("reply", reply); 1632 1633 sp<AMessage> response; 1634 status_t err = msg->postAndAwaitResponse(&response); 1635 return err; 1636} 1637 1638status_t NuPlayer::getSelectedTrack(int32_t type, Parcel* reply) const { 1639 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id()); 1640 msg->setPointer("reply", reply); 1641 msg->setInt32("type", type); 1642 1643 sp<AMessage> response; 1644 status_t err = msg->postAndAwaitResponse(&response); 1645 if (err == OK && response != NULL) { 1646 CHECK(response->findInt32("err", &err)); 1647 } 1648 return err; 1649} 1650 1651status_t NuPlayer::selectTrack(size_t trackIndex, bool select, int64_t timeUs) { 1652 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id()); 1653 msg->setSize("trackIndex", trackIndex); 1654 msg->setInt32("select", select); 1655 msg->setInt64("timeUs", timeUs); 1656 1657 sp<AMessage> response; 1658 status_t err = msg->postAndAwaitResponse(&response); 1659 1660 if (err != OK) { 1661 return err; 1662 } 1663 1664 if (!response->findInt32("err", &err)) { 1665 err = OK; 1666 } 1667 1668 return err; 1669} 1670 1671status_t NuPlayer::getCurrentPosition(int64_t *mediaUs) { 1672 sp<Renderer> renderer = mRenderer; 1673 if (renderer == NULL) { 1674 return NO_INIT; 1675 } 1676 1677 return renderer->getCurrentPosition(mediaUs); 1678} 1679 1680void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) { 1681 *numFramesTotal = mNumFramesTotal; 1682 *numFramesDropped = mNumFramesDropped; 1683} 1684 1685sp<MetaData> NuPlayer::getFileMeta() { 1686 return mSource->getFileFormatMeta(); 1687} 1688 1689void NuPlayer::schedulePollDuration() { 1690 sp<AMessage> msg = new AMessage(kWhatPollDuration, id()); 1691 msg->setInt32("generation", mPollDurationGeneration); 1692 msg->post(); 1693} 1694 1695void NuPlayer::cancelPollDuration() { 1696 ++mPollDurationGeneration; 1697} 1698 1699void NuPlayer::processDeferredActions() { 1700 while (!mDeferredActions.empty()) { 1701 // We won't execute any deferred actions until we're no longer in 1702 // an intermediate state, i.e. one more more decoders are currently 1703 // flushing or shutting down. 1704 1705 if (mFlushingAudio != NONE || mFlushingVideo != NONE) { 1706 // We're currently flushing, postpone the reset until that's 1707 // completed. 1708 1709 ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d", 1710 mFlushingAudio, mFlushingVideo); 1711 1712 break; 1713 } 1714 1715 sp<Action> action = *mDeferredActions.begin(); 1716 mDeferredActions.erase(mDeferredActions.begin()); 1717 1718 action->execute(this); 1719 } 1720} 1721 1722void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) { 1723 ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), needNotify(%d)", 1724 seekTimeUs, 1725 seekTimeUs / 1E6, 1726 needNotify); 1727 1728 if (mSource == NULL) { 1729 // This happens when reset occurs right before the loop mode 1730 // asynchronously seeks to the start of the stream. 1731 LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL, 1732 "mSource is NULL and decoders not NULL audio(%p) video(%p)", 1733 mAudioDecoder.get(), mVideoDecoder.get()); 1734 return; 1735 } 1736 mSource->seekTo(seekTimeUs); 1737 ++mTimedTextGeneration; 1738 1739 if (mDriver != NULL) { 1740 sp<NuPlayerDriver> driver = mDriver.promote(); 1741 if (driver != NULL) { 1742 if (needNotify) { 1743 driver->notifySeekComplete(); 1744 } 1745 } 1746 } 1747 1748 // everything's flushed, continue playback. 1749} 1750 1751void NuPlayer::performDecoderFlush(FlushCommand audio, FlushCommand video) { 1752 ALOGV("performDecoderFlush audio=%d, video=%d", audio, video); 1753 1754 if ((audio == FLUSH_CMD_NONE || mAudioDecoder == NULL) 1755 && (video == FLUSH_CMD_NONE || mVideoDecoder == NULL)) { 1756 return; 1757 } 1758 1759 mTimeDiscontinuityPending = true; 1760 1761 if (audio != FLUSH_CMD_NONE && mAudioDecoder != NULL) { 1762 flushDecoder(true /* audio */, (audio == FLUSH_CMD_SHUTDOWN)); 1763 } 1764 1765 if (video != FLUSH_CMD_NONE && mVideoDecoder != NULL) { 1766 flushDecoder(false /* audio */, (video == FLUSH_CMD_SHUTDOWN)); 1767 } 1768} 1769 1770void NuPlayer::performReset() { 1771 ALOGV("performReset"); 1772 1773 CHECK(mAudioDecoder == NULL); 1774 CHECK(mVideoDecoder == NULL); 1775 1776 cancelPollDuration(); 1777 1778 ++mScanSourcesGeneration; 1779 mScanSourcesPending = false; 1780 1781 if (mRendererLooper != NULL) { 1782 if (mRenderer != NULL) { 1783 mRendererLooper->unregisterHandler(mRenderer->id()); 1784 } 1785 mRendererLooper->stop(); 1786 mRendererLooper.clear(); 1787 } 1788 mRenderer.clear(); 1789 ++mRendererGeneration; 1790 1791 if (mSource != NULL) { 1792 mSource->stop(); 1793 1794 mSource.clear(); 1795 } 1796 1797 if (mDriver != NULL) { 1798 sp<NuPlayerDriver> driver = mDriver.promote(); 1799 if (driver != NULL) { 1800 driver->notifyResetComplete(); 1801 } 1802 } 1803 1804 mStarted = false; 1805} 1806 1807void NuPlayer::performScanSources() { 1808 ALOGV("performScanSources"); 1809 1810 if (!mStarted) { 1811 return; 1812 } 1813 1814 if (mAudioDecoder == NULL || mVideoDecoder == NULL) { 1815 postScanSources(); 1816 } 1817} 1818 1819void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) { 1820 ALOGV("performSetSurface"); 1821 1822 mNativeWindow = wrapper; 1823 1824 // XXX - ignore error from setVideoScalingMode for now 1825 setVideoScalingMode(mVideoScalingMode); 1826 1827 if (mDriver != NULL) { 1828 sp<NuPlayerDriver> driver = mDriver.promote(); 1829 if (driver != NULL) { 1830 driver->notifySetSurfaceComplete(); 1831 } 1832 } 1833} 1834 1835void NuPlayer::onSourceNotify(const sp<AMessage> &msg) { 1836 int32_t what; 1837 CHECK(msg->findInt32("what", &what)); 1838 1839 switch (what) { 1840 case Source::kWhatPrepared: 1841 { 1842 if (mSource == NULL) { 1843 // This is a stale notification from a source that was 1844 // asynchronously preparing when the client called reset(). 1845 // We handled the reset, the source is gone. 1846 break; 1847 } 1848 1849 int32_t err; 1850 CHECK(msg->findInt32("err", &err)); 1851 1852 sp<NuPlayerDriver> driver = mDriver.promote(); 1853 if (driver != NULL) { 1854 // notify duration first, so that it's definitely set when 1855 // the app received the "prepare complete" callback. 1856 int64_t durationUs; 1857 if (mSource->getDuration(&durationUs) == OK) { 1858 driver->notifyDuration(durationUs); 1859 } 1860 driver->notifyPrepareCompleted(err); 1861 } 1862 1863 break; 1864 } 1865 1866 case Source::kWhatFlagsChanged: 1867 { 1868 uint32_t flags; 1869 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 1870 1871 sp<NuPlayerDriver> driver = mDriver.promote(); 1872 if (driver != NULL) { 1873 driver->notifyFlagsChanged(flags); 1874 } 1875 1876 if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION) 1877 && (!(flags & Source::FLAG_DYNAMIC_DURATION))) { 1878 cancelPollDuration(); 1879 } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION) 1880 && (flags & Source::FLAG_DYNAMIC_DURATION) 1881 && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { 1882 schedulePollDuration(); 1883 } 1884 1885 mSourceFlags = flags; 1886 break; 1887 } 1888 1889 case Source::kWhatVideoSizeChanged: 1890 { 1891 sp<AMessage> format; 1892 CHECK(msg->findMessage("format", &format)); 1893 1894 updateVideoSize(format); 1895 break; 1896 } 1897 1898 case Source::kWhatBufferingUpdate: 1899 { 1900 int32_t percentage; 1901 CHECK(msg->findInt32("percentage", &percentage)); 1902 1903 notifyListener(MEDIA_BUFFERING_UPDATE, percentage, 0); 1904 break; 1905 } 1906 1907 case Source::kWhatBufferingStart: 1908 { 1909 notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0); 1910 break; 1911 } 1912 1913 case Source::kWhatBufferingEnd: 1914 { 1915 notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0); 1916 break; 1917 } 1918 1919 case Source::kWhatSubtitleData: 1920 { 1921 sp<ABuffer> buffer; 1922 CHECK(msg->findBuffer("buffer", &buffer)); 1923 1924 sendSubtitleData(buffer, 0 /* baseIndex */); 1925 break; 1926 } 1927 1928 case Source::kWhatTimedTextData: 1929 { 1930 int32_t generation; 1931 if (msg->findInt32("generation", &generation) 1932 && generation != mTimedTextGeneration) { 1933 break; 1934 } 1935 1936 sp<ABuffer> buffer; 1937 CHECK(msg->findBuffer("buffer", &buffer)); 1938 1939 sp<NuPlayerDriver> driver = mDriver.promote(); 1940 if (driver == NULL) { 1941 break; 1942 } 1943 1944 int posMs; 1945 int64_t timeUs, posUs; 1946 driver->getCurrentPosition(&posMs); 1947 posUs = posMs * 1000; 1948 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 1949 1950 if (posUs < timeUs) { 1951 if (!msg->findInt32("generation", &generation)) { 1952 msg->setInt32("generation", mTimedTextGeneration); 1953 } 1954 msg->post(timeUs - posUs); 1955 } else { 1956 sendTimedTextData(buffer); 1957 } 1958 break; 1959 } 1960 1961 case Source::kWhatQueueDecoderShutdown: 1962 { 1963 int32_t audio, video; 1964 CHECK(msg->findInt32("audio", &audio)); 1965 CHECK(msg->findInt32("video", &video)); 1966 1967 sp<AMessage> reply; 1968 CHECK(msg->findMessage("reply", &reply)); 1969 1970 queueDecoderShutdown(audio, video, reply); 1971 break; 1972 } 1973 1974 case Source::kWhatDrmNoLicense: 1975 { 1976 notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); 1977 break; 1978 } 1979 1980 default: 1981 TRESPASS(); 1982 } 1983} 1984 1985void NuPlayer::onClosedCaptionNotify(const sp<AMessage> &msg) { 1986 int32_t what; 1987 CHECK(msg->findInt32("what", &what)); 1988 1989 switch (what) { 1990 case NuPlayer::CCDecoder::kWhatClosedCaptionData: 1991 { 1992 sp<ABuffer> buffer; 1993 CHECK(msg->findBuffer("buffer", &buffer)); 1994 1995 size_t inbandTracks = 0; 1996 if (mSource != NULL) { 1997 inbandTracks = mSource->getTrackCount(); 1998 } 1999 2000 sendSubtitleData(buffer, inbandTracks); 2001 break; 2002 } 2003 2004 case NuPlayer::CCDecoder::kWhatTrackAdded: 2005 { 2006 notifyListener(MEDIA_INFO, MEDIA_INFO_METADATA_UPDATE, 0); 2007 2008 break; 2009 } 2010 2011 default: 2012 TRESPASS(); 2013 } 2014 2015 2016} 2017 2018void NuPlayer::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) { 2019 int32_t trackIndex; 2020 int64_t timeUs, durationUs; 2021 CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex)); 2022 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 2023 CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); 2024 2025 Parcel in; 2026 in.writeInt32(trackIndex + baseIndex); 2027 in.writeInt64(timeUs); 2028 in.writeInt64(durationUs); 2029 in.writeInt32(buffer->size()); 2030 in.writeInt32(buffer->size()); 2031 in.write(buffer->data(), buffer->size()); 2032 2033 notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in); 2034} 2035 2036void NuPlayer::sendTimedTextData(const sp<ABuffer> &buffer) { 2037 const void *data; 2038 size_t size = 0; 2039 int64_t timeUs; 2040 int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS; 2041 2042 AString mime; 2043 CHECK(buffer->meta()->findString("mime", &mime)); 2044 CHECK(strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP) == 0); 2045 2046 data = buffer->data(); 2047 size = buffer->size(); 2048 2049 Parcel parcel; 2050 if (size > 0) { 2051 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 2052 flag |= TextDescriptions::IN_BAND_TEXT_3GPP; 2053 TextDescriptions::getParcelOfDescriptions( 2054 (const uint8_t *)data, size, flag, timeUs / 1000, &parcel); 2055 } 2056 2057 if ((parcel.dataSize() > 0)) { 2058 notifyListener(MEDIA_TIMED_TEXT, 0, 0, &parcel); 2059 } else { // send an empty timed text 2060 notifyListener(MEDIA_TIMED_TEXT, 0, 0); 2061 } 2062} 2063//////////////////////////////////////////////////////////////////////////////// 2064 2065sp<AMessage> NuPlayer::Source::getFormat(bool audio) { 2066 sp<MetaData> meta = getFormatMeta(audio); 2067 2068 if (meta == NULL) { 2069 return NULL; 2070 } 2071 2072 sp<AMessage> msg = new AMessage; 2073 2074 if(convertMetaDataToMessage(meta, &msg) == OK) { 2075 return msg; 2076 } 2077 return NULL; 2078} 2079 2080void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) { 2081 sp<AMessage> notify = dupNotify(); 2082 notify->setInt32("what", kWhatFlagsChanged); 2083 notify->setInt32("flags", flags); 2084 notify->post(); 2085} 2086 2087void NuPlayer::Source::notifyVideoSizeChanged(const sp<AMessage> &format) { 2088 sp<AMessage> notify = dupNotify(); 2089 notify->setInt32("what", kWhatVideoSizeChanged); 2090 notify->setMessage("format", format); 2091 notify->post(); 2092} 2093 2094void NuPlayer::Source::notifyPrepared(status_t err) { 2095 sp<AMessage> notify = dupNotify(); 2096 notify->setInt32("what", kWhatPrepared); 2097 notify->setInt32("err", err); 2098 notify->post(); 2099} 2100 2101void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) { 2102 TRESPASS(); 2103} 2104 2105} // namespace android 2106