NuPlayer.cpp revision 574aed902443d41581684dc8bc5ddd2e067f4cdf
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 } else if (err == ERROR_END_OF_STREAM 1349 && doBufferAggregation && (mAggregateBuffer != NULL)) { 1350 // send out the last bit of aggregated data 1351 reply->setBuffer("buffer", mAggregateBuffer); 1352 mAggregateBuffer.clear(); 1353 err = OK; 1354 } 1355 1356 reply->setInt32("err", err); 1357 reply->post(); 1358 return OK; 1359 } 1360 1361 if (!audio) { 1362 ++mNumFramesTotal; 1363 } 1364 1365 dropAccessUnit = false; 1366 if (!audio 1367 && !(mSourceFlags & Source::FLAG_SECURE) 1368 && mRenderer->getVideoLateByUs() > 100000ll 1369 && mVideoIsAVC 1370 && !IsAVCReferenceFrame(accessUnit)) { 1371 dropAccessUnit = true; 1372 ++mNumFramesDropped; 1373 } 1374 1375 size_t smallSize = accessUnit->size(); 1376 needMoreData = false; 1377 if (doBufferAggregation && (mAggregateBuffer == NULL) 1378 // Don't bother if only room for a few small buffers. 1379 && (smallSize < (kAggregateBufferSizeBytes / 3))) { 1380 // Create a larger buffer for combining smaller buffers from the extractor. 1381 mAggregateBuffer = new ABuffer(kAggregateBufferSizeBytes); 1382 mAggregateBuffer->setRange(0, 0); // start empty 1383 } 1384 1385 if (doBufferAggregation && (mAggregateBuffer != NULL)) { 1386 int64_t timeUs; 1387 int64_t dummy; 1388 bool smallTimestampValid = accessUnit->meta()->findInt64("timeUs", &timeUs); 1389 bool bigTimestampValid = mAggregateBuffer->meta()->findInt64("timeUs", &dummy); 1390 // Will the smaller buffer fit? 1391 size_t bigSize = mAggregateBuffer->size(); 1392 size_t roomLeft = mAggregateBuffer->capacity() - bigSize; 1393 // Should we save this small buffer for the next big buffer? 1394 // If the first small buffer did not have a timestamp then save 1395 // any buffer that does have a timestamp until the next big buffer. 1396 if ((smallSize > roomLeft) 1397 || (!bigTimestampValid && (bigSize > 0) && smallTimestampValid)) { 1398 mPendingAudioErr = err; 1399 mPendingAudioAccessUnit = accessUnit; 1400 accessUnit.clear(); 1401 } else { 1402 // Grab time from first small buffer if available. 1403 if ((bigSize == 0) && smallTimestampValid) { 1404 mAggregateBuffer->meta()->setInt64("timeUs", timeUs); 1405 } 1406 // Append small buffer to the bigger buffer. 1407 memcpy(mAggregateBuffer->base() + bigSize, accessUnit->data(), smallSize); 1408 bigSize += smallSize; 1409 mAggregateBuffer->setRange(0, bigSize); 1410 1411 // Keep looping until we run out of room in the mAggregateBuffer. 1412 needMoreData = true; 1413 1414 ALOGV("feedDecoderInputData() smallSize = %zu, bigSize = %zu, capacity = %zu", 1415 smallSize, bigSize, mAggregateBuffer->capacity()); 1416 } 1417 } 1418 } while (dropAccessUnit || needMoreData); 1419 1420 // ALOGV("returned a valid buffer of %s data", audio ? "audio" : "video"); 1421 1422#if 0 1423 int64_t mediaTimeUs; 1424 CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); 1425 ALOGV("feeding %s input buffer at media time %.2f secs", 1426 audio ? "audio" : "video", 1427 mediaTimeUs / 1E6); 1428#endif 1429 1430 if (!audio) { 1431 mCCDecoder->decode(accessUnit); 1432 } 1433 1434 if (doBufferAggregation && (mAggregateBuffer != NULL)) { 1435 ALOGV("feedDecoderInputData() reply with aggregated buffer, %zu", 1436 mAggregateBuffer->size()); 1437 reply->setBuffer("buffer", mAggregateBuffer); 1438 mAggregateBuffer.clear(); 1439 } else { 1440 reply->setBuffer("buffer", accessUnit); 1441 } 1442 1443 reply->post(); 1444 1445 return OK; 1446} 1447 1448void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { 1449 // ALOGV("renderBuffer %s", audio ? "audio" : "video"); 1450 1451 if ((audio && mFlushingAudio != NONE) 1452 || (!audio && mFlushingVideo != NONE)) { 1453 // We're currently attempting to flush the decoder, in order 1454 // to complete this, the decoder wants all its buffers back, 1455 // so we don't want any output buffers it sent us (from before 1456 // we initiated the flush) to be stuck in the renderer's queue. 1457 1458 ALOGV("we're still flushing the %s decoder, sending its output buffer" 1459 " right back.", audio ? "audio" : "video"); 1460 1461 return; 1462 } 1463 1464 int64_t mediaTimeUs; 1465 CHECK(msg->findInt64("timeUs", &mediaTimeUs)); 1466 1467 if (!audio && mCCDecoder->isSelected()) { 1468 mCCDecoder->display(mediaTimeUs); 1469 } 1470} 1471 1472void NuPlayer::updateVideoSize( 1473 const sp<AMessage> &inputFormat, 1474 const sp<AMessage> &outputFormat) { 1475 if (inputFormat == NULL) { 1476 ALOGW("Unknown video size, reporting 0x0!"); 1477 notifyListener(MEDIA_SET_VIDEO_SIZE, 0, 0); 1478 return; 1479 } 1480 1481 int32_t displayWidth, displayHeight; 1482 int32_t cropLeft, cropTop, cropRight, cropBottom; 1483 1484 if (outputFormat != NULL) { 1485 int32_t width, height; 1486 CHECK(outputFormat->findInt32("width", &width)); 1487 CHECK(outputFormat->findInt32("height", &height)); 1488 1489 int32_t cropLeft, cropTop, cropRight, cropBottom; 1490 CHECK(outputFormat->findRect( 1491 "crop", 1492 &cropLeft, &cropTop, &cropRight, &cropBottom)); 1493 1494 displayWidth = cropRight - cropLeft + 1; 1495 displayHeight = cropBottom - cropTop + 1; 1496 1497 ALOGV("Video output format changed to %d x %d " 1498 "(crop: %d x %d @ (%d, %d))", 1499 width, height, 1500 displayWidth, 1501 displayHeight, 1502 cropLeft, cropTop); 1503 } else { 1504 CHECK(inputFormat->findInt32("width", &displayWidth)); 1505 CHECK(inputFormat->findInt32("height", &displayHeight)); 1506 1507 ALOGV("Video input format %d x %d", displayWidth, displayHeight); 1508 } 1509 1510 // Take into account sample aspect ratio if necessary: 1511 int32_t sarWidth, sarHeight; 1512 if (inputFormat->findInt32("sar-width", &sarWidth) 1513 && inputFormat->findInt32("sar-height", &sarHeight)) { 1514 ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight); 1515 1516 displayWidth = (displayWidth * sarWidth) / sarHeight; 1517 1518 ALOGV("display dimensions %d x %d", displayWidth, displayHeight); 1519 } 1520 1521 int32_t rotationDegrees; 1522 if (!inputFormat->findInt32("rotation-degrees", &rotationDegrees)) { 1523 rotationDegrees = 0; 1524 } 1525 1526 if (rotationDegrees == 90 || rotationDegrees == 270) { 1527 int32_t tmp = displayWidth; 1528 displayWidth = displayHeight; 1529 displayHeight = tmp; 1530 } 1531 1532 notifyListener( 1533 MEDIA_SET_VIDEO_SIZE, 1534 displayWidth, 1535 displayHeight); 1536} 1537 1538void NuPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *in) { 1539 if (mDriver == NULL) { 1540 return; 1541 } 1542 1543 sp<NuPlayerDriver> driver = mDriver.promote(); 1544 1545 if (driver == NULL) { 1546 return; 1547 } 1548 1549 driver->notifyListener(msg, ext1, ext2, in); 1550} 1551 1552void NuPlayer::flushDecoder( 1553 bool audio, bool needShutdown, const sp<AMessage> &newFormat) { 1554 ALOGV("[%s] flushDecoder needShutdown=%d", 1555 audio ? "audio" : "video", needShutdown); 1556 1557 const sp<Decoder> &decoder = getDecoder(audio); 1558 if (decoder == NULL) { 1559 ALOGI("flushDecoder %s without decoder present", 1560 audio ? "audio" : "video"); 1561 return; 1562 } 1563 1564 // Make sure we don't continue to scan sources until we finish flushing. 1565 ++mScanSourcesGeneration; 1566 mScanSourcesPending = false; 1567 1568 decoder->signalFlush(newFormat); 1569 1570 FlushStatus newStatus = 1571 needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER; 1572 1573 mFlushComplete[audio][false /* isDecoder */] = false; 1574 mFlushComplete[audio][true /* isDecoder */] = false; 1575 if (audio) { 1576 ALOGE_IF(mFlushingAudio != NONE, 1577 "audio flushDecoder() is called in state %d", mFlushingAudio); 1578 mFlushingAudio = newStatus; 1579 } else { 1580 ALOGE_IF(mFlushingVideo != NONE, 1581 "video flushDecoder() is called in state %d", mFlushingVideo); 1582 mFlushingVideo = newStatus; 1583 1584 if (mCCDecoder != NULL) { 1585 mCCDecoder->flush(); 1586 } 1587 } 1588} 1589 1590void NuPlayer::updateDecoderFormatWithoutFlush( 1591 bool audio, const sp<AMessage> &format) { 1592 ALOGV("[%s] updateDecoderFormatWithoutFlush", audio ? "audio" : "video"); 1593 1594 const sp<Decoder> &decoder = getDecoder(audio); 1595 if (decoder == NULL) { 1596 ALOGI("updateDecoderFormatWithoutFlush %s without decoder present", 1597 audio ? "audio" : "video"); 1598 return; 1599 } 1600 1601 decoder->signalUpdateFormat(format); 1602} 1603 1604void NuPlayer::queueDecoderShutdown( 1605 bool audio, bool video, const sp<AMessage> &reply) { 1606 ALOGI("queueDecoderShutdown audio=%d, video=%d", audio, video); 1607 1608 mDeferredActions.push_back( 1609 new FlushDecoderAction( 1610 audio ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE, 1611 video ? FLUSH_CMD_SHUTDOWN : FLUSH_CMD_NONE)); 1612 1613 mDeferredActions.push_back( 1614 new SimpleAction(&NuPlayer::performScanSources)); 1615 1616 mDeferredActions.push_back(new PostMessageAction(reply)); 1617 1618 processDeferredActions(); 1619} 1620 1621status_t NuPlayer::setVideoScalingMode(int32_t mode) { 1622 mVideoScalingMode = mode; 1623 if (mNativeWindow != NULL) { 1624 status_t ret = native_window_set_scaling_mode( 1625 mNativeWindow->getNativeWindow().get(), mVideoScalingMode); 1626 if (ret != OK) { 1627 ALOGE("Failed to set scaling mode (%d): %s", 1628 -ret, strerror(-ret)); 1629 return ret; 1630 } 1631 } 1632 return OK; 1633} 1634 1635status_t NuPlayer::getTrackInfo(Parcel* reply) const { 1636 sp<AMessage> msg = new AMessage(kWhatGetTrackInfo, id()); 1637 msg->setPointer("reply", reply); 1638 1639 sp<AMessage> response; 1640 status_t err = msg->postAndAwaitResponse(&response); 1641 return err; 1642} 1643 1644status_t NuPlayer::getSelectedTrack(int32_t type, Parcel* reply) const { 1645 sp<AMessage> msg = new AMessage(kWhatGetSelectedTrack, id()); 1646 msg->setPointer("reply", reply); 1647 msg->setInt32("type", type); 1648 1649 sp<AMessage> response; 1650 status_t err = msg->postAndAwaitResponse(&response); 1651 if (err == OK && response != NULL) { 1652 CHECK(response->findInt32("err", &err)); 1653 } 1654 return err; 1655} 1656 1657status_t NuPlayer::selectTrack(size_t trackIndex, bool select, int64_t timeUs) { 1658 sp<AMessage> msg = new AMessage(kWhatSelectTrack, id()); 1659 msg->setSize("trackIndex", trackIndex); 1660 msg->setInt32("select", select); 1661 msg->setInt64("timeUs", timeUs); 1662 1663 sp<AMessage> response; 1664 status_t err = msg->postAndAwaitResponse(&response); 1665 1666 if (err != OK) { 1667 return err; 1668 } 1669 1670 if (!response->findInt32("err", &err)) { 1671 err = OK; 1672 } 1673 1674 return err; 1675} 1676 1677status_t NuPlayer::getCurrentPosition(int64_t *mediaUs) { 1678 sp<Renderer> renderer = mRenderer; 1679 if (renderer == NULL) { 1680 return NO_INIT; 1681 } 1682 1683 return renderer->getCurrentPosition(mediaUs); 1684} 1685 1686void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) { 1687 *numFramesTotal = mNumFramesTotal; 1688 *numFramesDropped = mNumFramesDropped; 1689} 1690 1691sp<MetaData> NuPlayer::getFileMeta() { 1692 return mSource->getFileFormatMeta(); 1693} 1694 1695void NuPlayer::schedulePollDuration() { 1696 sp<AMessage> msg = new AMessage(kWhatPollDuration, id()); 1697 msg->setInt32("generation", mPollDurationGeneration); 1698 msg->post(); 1699} 1700 1701void NuPlayer::cancelPollDuration() { 1702 ++mPollDurationGeneration; 1703} 1704 1705void NuPlayer::processDeferredActions() { 1706 while (!mDeferredActions.empty()) { 1707 // We won't execute any deferred actions until we're no longer in 1708 // an intermediate state, i.e. one more more decoders are currently 1709 // flushing or shutting down. 1710 1711 if (mFlushingAudio != NONE || mFlushingVideo != NONE) { 1712 // We're currently flushing, postpone the reset until that's 1713 // completed. 1714 1715 ALOGV("postponing action mFlushingAudio=%d, mFlushingVideo=%d", 1716 mFlushingAudio, mFlushingVideo); 1717 1718 break; 1719 } 1720 1721 sp<Action> action = *mDeferredActions.begin(); 1722 mDeferredActions.erase(mDeferredActions.begin()); 1723 1724 action->execute(this); 1725 } 1726} 1727 1728void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) { 1729 ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), needNotify(%d)", 1730 seekTimeUs, 1731 seekTimeUs / 1E6, 1732 needNotify); 1733 1734 if (mSource == NULL) { 1735 // This happens when reset occurs right before the loop mode 1736 // asynchronously seeks to the start of the stream. 1737 LOG_ALWAYS_FATAL_IF(mAudioDecoder != NULL || mVideoDecoder != NULL, 1738 "mSource is NULL and decoders not NULL audio(%p) video(%p)", 1739 mAudioDecoder.get(), mVideoDecoder.get()); 1740 return; 1741 } 1742 mSource->seekTo(seekTimeUs); 1743 ++mTimedTextGeneration; 1744 1745 if (mDriver != NULL) { 1746 sp<NuPlayerDriver> driver = mDriver.promote(); 1747 if (driver != NULL) { 1748 if (needNotify) { 1749 driver->notifySeekComplete(); 1750 } 1751 } 1752 } 1753 1754 // everything's flushed, continue playback. 1755} 1756 1757void NuPlayer::performDecoderFlush(FlushCommand audio, FlushCommand video) { 1758 ALOGV("performDecoderFlush audio=%d, video=%d", audio, video); 1759 1760 if ((audio == FLUSH_CMD_NONE || mAudioDecoder == NULL) 1761 && (video == FLUSH_CMD_NONE || mVideoDecoder == NULL)) { 1762 return; 1763 } 1764 1765 mTimeDiscontinuityPending = true; 1766 1767 if (audio != FLUSH_CMD_NONE && mAudioDecoder != NULL) { 1768 flushDecoder(true /* audio */, (audio == FLUSH_CMD_SHUTDOWN)); 1769 } 1770 1771 if (video != FLUSH_CMD_NONE && mVideoDecoder != NULL) { 1772 flushDecoder(false /* audio */, (video == FLUSH_CMD_SHUTDOWN)); 1773 } 1774} 1775 1776void NuPlayer::performReset() { 1777 ALOGV("performReset"); 1778 1779 CHECK(mAudioDecoder == NULL); 1780 CHECK(mVideoDecoder == NULL); 1781 1782 cancelPollDuration(); 1783 1784 ++mScanSourcesGeneration; 1785 mScanSourcesPending = false; 1786 1787 if (mRendererLooper != NULL) { 1788 if (mRenderer != NULL) { 1789 mRendererLooper->unregisterHandler(mRenderer->id()); 1790 } 1791 mRendererLooper->stop(); 1792 mRendererLooper.clear(); 1793 } 1794 mRenderer.clear(); 1795 ++mRendererGeneration; 1796 1797 if (mSource != NULL) { 1798 mSource->stop(); 1799 1800 mSource.clear(); 1801 } 1802 1803 if (mDriver != NULL) { 1804 sp<NuPlayerDriver> driver = mDriver.promote(); 1805 if (driver != NULL) { 1806 driver->notifyResetComplete(); 1807 } 1808 } 1809 1810 mStarted = false; 1811} 1812 1813void NuPlayer::performScanSources() { 1814 ALOGV("performScanSources"); 1815 1816 if (!mStarted) { 1817 return; 1818 } 1819 1820 if (mAudioDecoder == NULL || mVideoDecoder == NULL) { 1821 postScanSources(); 1822 } 1823} 1824 1825void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) { 1826 ALOGV("performSetSurface"); 1827 1828 mNativeWindow = wrapper; 1829 1830 // XXX - ignore error from setVideoScalingMode for now 1831 setVideoScalingMode(mVideoScalingMode); 1832 1833 if (mDriver != NULL) { 1834 sp<NuPlayerDriver> driver = mDriver.promote(); 1835 if (driver != NULL) { 1836 driver->notifySetSurfaceComplete(); 1837 } 1838 } 1839} 1840 1841void NuPlayer::onSourceNotify(const sp<AMessage> &msg) { 1842 int32_t what; 1843 CHECK(msg->findInt32("what", &what)); 1844 1845 switch (what) { 1846 case Source::kWhatPrepared: 1847 { 1848 if (mSource == NULL) { 1849 // This is a stale notification from a source that was 1850 // asynchronously preparing when the client called reset(). 1851 // We handled the reset, the source is gone. 1852 break; 1853 } 1854 1855 int32_t err; 1856 CHECK(msg->findInt32("err", &err)); 1857 1858 sp<NuPlayerDriver> driver = mDriver.promote(); 1859 if (driver != NULL) { 1860 // notify duration first, so that it's definitely set when 1861 // the app received the "prepare complete" callback. 1862 int64_t durationUs; 1863 if (mSource->getDuration(&durationUs) == OK) { 1864 driver->notifyDuration(durationUs); 1865 } 1866 driver->notifyPrepareCompleted(err); 1867 } 1868 1869 break; 1870 } 1871 1872 case Source::kWhatFlagsChanged: 1873 { 1874 uint32_t flags; 1875 CHECK(msg->findInt32("flags", (int32_t *)&flags)); 1876 1877 sp<NuPlayerDriver> driver = mDriver.promote(); 1878 if (driver != NULL) { 1879 driver->notifyFlagsChanged(flags); 1880 } 1881 1882 if ((mSourceFlags & Source::FLAG_DYNAMIC_DURATION) 1883 && (!(flags & Source::FLAG_DYNAMIC_DURATION))) { 1884 cancelPollDuration(); 1885 } else if (!(mSourceFlags & Source::FLAG_DYNAMIC_DURATION) 1886 && (flags & Source::FLAG_DYNAMIC_DURATION) 1887 && (mAudioDecoder != NULL || mVideoDecoder != NULL)) { 1888 schedulePollDuration(); 1889 } 1890 1891 mSourceFlags = flags; 1892 break; 1893 } 1894 1895 case Source::kWhatVideoSizeChanged: 1896 { 1897 sp<AMessage> format; 1898 CHECK(msg->findMessage("format", &format)); 1899 1900 updateVideoSize(format); 1901 break; 1902 } 1903 1904 case Source::kWhatBufferingUpdate: 1905 { 1906 int32_t percentage; 1907 CHECK(msg->findInt32("percentage", &percentage)); 1908 1909 notifyListener(MEDIA_BUFFERING_UPDATE, percentage, 0); 1910 break; 1911 } 1912 1913 case Source::kWhatBufferingStart: 1914 { 1915 notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0); 1916 break; 1917 } 1918 1919 case Source::kWhatBufferingEnd: 1920 { 1921 notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0); 1922 break; 1923 } 1924 1925 case Source::kWhatSubtitleData: 1926 { 1927 sp<ABuffer> buffer; 1928 CHECK(msg->findBuffer("buffer", &buffer)); 1929 1930 sendSubtitleData(buffer, 0 /* baseIndex */); 1931 break; 1932 } 1933 1934 case Source::kWhatTimedTextData: 1935 { 1936 int32_t generation; 1937 if (msg->findInt32("generation", &generation) 1938 && generation != mTimedTextGeneration) { 1939 break; 1940 } 1941 1942 sp<ABuffer> buffer; 1943 CHECK(msg->findBuffer("buffer", &buffer)); 1944 1945 sp<NuPlayerDriver> driver = mDriver.promote(); 1946 if (driver == NULL) { 1947 break; 1948 } 1949 1950 int posMs; 1951 int64_t timeUs, posUs; 1952 driver->getCurrentPosition(&posMs); 1953 posUs = posMs * 1000; 1954 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 1955 1956 if (posUs < timeUs) { 1957 if (!msg->findInt32("generation", &generation)) { 1958 msg->setInt32("generation", mTimedTextGeneration); 1959 } 1960 msg->post(timeUs - posUs); 1961 } else { 1962 sendTimedTextData(buffer); 1963 } 1964 break; 1965 } 1966 1967 case Source::kWhatQueueDecoderShutdown: 1968 { 1969 int32_t audio, video; 1970 CHECK(msg->findInt32("audio", &audio)); 1971 CHECK(msg->findInt32("video", &video)); 1972 1973 sp<AMessage> reply; 1974 CHECK(msg->findMessage("reply", &reply)); 1975 1976 queueDecoderShutdown(audio, video, reply); 1977 break; 1978 } 1979 1980 case Source::kWhatDrmNoLicense: 1981 { 1982 notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); 1983 break; 1984 } 1985 1986 default: 1987 TRESPASS(); 1988 } 1989} 1990 1991void NuPlayer::onClosedCaptionNotify(const sp<AMessage> &msg) { 1992 int32_t what; 1993 CHECK(msg->findInt32("what", &what)); 1994 1995 switch (what) { 1996 case NuPlayer::CCDecoder::kWhatClosedCaptionData: 1997 { 1998 sp<ABuffer> buffer; 1999 CHECK(msg->findBuffer("buffer", &buffer)); 2000 2001 size_t inbandTracks = 0; 2002 if (mSource != NULL) { 2003 inbandTracks = mSource->getTrackCount(); 2004 } 2005 2006 sendSubtitleData(buffer, inbandTracks); 2007 break; 2008 } 2009 2010 case NuPlayer::CCDecoder::kWhatTrackAdded: 2011 { 2012 notifyListener(MEDIA_INFO, MEDIA_INFO_METADATA_UPDATE, 0); 2013 2014 break; 2015 } 2016 2017 default: 2018 TRESPASS(); 2019 } 2020 2021 2022} 2023 2024void NuPlayer::sendSubtitleData(const sp<ABuffer> &buffer, int32_t baseIndex) { 2025 int32_t trackIndex; 2026 int64_t timeUs, durationUs; 2027 CHECK(buffer->meta()->findInt32("trackIndex", &trackIndex)); 2028 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 2029 CHECK(buffer->meta()->findInt64("durationUs", &durationUs)); 2030 2031 Parcel in; 2032 in.writeInt32(trackIndex + baseIndex); 2033 in.writeInt64(timeUs); 2034 in.writeInt64(durationUs); 2035 in.writeInt32(buffer->size()); 2036 in.writeInt32(buffer->size()); 2037 in.write(buffer->data(), buffer->size()); 2038 2039 notifyListener(MEDIA_SUBTITLE_DATA, 0, 0, &in); 2040} 2041 2042void NuPlayer::sendTimedTextData(const sp<ABuffer> &buffer) { 2043 const void *data; 2044 size_t size = 0; 2045 int64_t timeUs; 2046 int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS; 2047 2048 AString mime; 2049 CHECK(buffer->meta()->findString("mime", &mime)); 2050 CHECK(strcasecmp(mime.c_str(), MEDIA_MIMETYPE_TEXT_3GPP) == 0); 2051 2052 data = buffer->data(); 2053 size = buffer->size(); 2054 2055 Parcel parcel; 2056 if (size > 0) { 2057 CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); 2058 flag |= TextDescriptions::IN_BAND_TEXT_3GPP; 2059 TextDescriptions::getParcelOfDescriptions( 2060 (const uint8_t *)data, size, flag, timeUs / 1000, &parcel); 2061 } 2062 2063 if ((parcel.dataSize() > 0)) { 2064 notifyListener(MEDIA_TIMED_TEXT, 0, 0, &parcel); 2065 } else { // send an empty timed text 2066 notifyListener(MEDIA_TIMED_TEXT, 0, 0); 2067 } 2068} 2069//////////////////////////////////////////////////////////////////////////////// 2070 2071sp<AMessage> NuPlayer::Source::getFormat(bool audio) { 2072 sp<MetaData> meta = getFormatMeta(audio); 2073 2074 if (meta == NULL) { 2075 return NULL; 2076 } 2077 2078 sp<AMessage> msg = new AMessage; 2079 2080 if(convertMetaDataToMessage(meta, &msg) == OK) { 2081 return msg; 2082 } 2083 return NULL; 2084} 2085 2086void NuPlayer::Source::notifyFlagsChanged(uint32_t flags) { 2087 sp<AMessage> notify = dupNotify(); 2088 notify->setInt32("what", kWhatFlagsChanged); 2089 notify->setInt32("flags", flags); 2090 notify->post(); 2091} 2092 2093void NuPlayer::Source::notifyVideoSizeChanged(const sp<AMessage> &format) { 2094 sp<AMessage> notify = dupNotify(); 2095 notify->setInt32("what", kWhatVideoSizeChanged); 2096 notify->setMessage("format", format); 2097 notify->post(); 2098} 2099 2100void NuPlayer::Source::notifyPrepared(status_t err) { 2101 sp<AMessage> notify = dupNotify(); 2102 notify->setInt32("what", kWhatPrepared); 2103 notify->setInt32("err", err); 2104 notify->post(); 2105} 2106 2107void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) { 2108 TRESPASS(); 2109} 2110 2111} // namespace android 2112