AwesomePlayer.cpp revision a6e6c70a3c5403e178741eee20c7742e736c4818
1/* 2 * Copyright (C) 2009 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#undef DEBUG_HDCP 18 19//#define LOG_NDEBUG 0 20#define LOG_TAG "AwesomePlayer" 21#define ATRACE_TAG ATRACE_TAG_VIDEO 22#include <inttypes.h> 23#include <utils/Log.h> 24#include <utils/Trace.h> 25 26#include <dlfcn.h> 27 28#include "include/AwesomePlayer.h" 29#include "include/DRMExtractor.h" 30#include "include/SoftwareRenderer.h" 31#include "include/NuCachedSource2.h" 32#include "include/ThrottledSource.h" 33#include "include/MPEG2TSExtractor.h" 34#include "include/WVMExtractor.h" 35 36#include <binder/IPCThreadState.h> 37#include <binder/IServiceManager.h> 38#include <media/IMediaPlayerService.h> 39#include <media/stagefright/foundation/hexdump.h> 40#include <media/stagefright/foundation/ADebug.h> 41#include <media/stagefright/timedtext/TimedTextDriver.h> 42#include <media/stagefright/AudioPlayer.h> 43#include <media/stagefright/ClockEstimator.h> 44#include <media/stagefright/DataSource.h> 45#include <media/stagefright/FileSource.h> 46#include <media/stagefright/MediaBuffer.h> 47#include <media/stagefright/MediaDefs.h> 48#include <media/stagefright/MediaExtractor.h> 49#include <media/stagefright/MediaSource.h> 50#include <media/stagefright/MetaData.h> 51#include <media/stagefright/OMXCodec.h> 52#include <media/stagefright/Utils.h> 53 54#include <gui/IGraphicBufferProducer.h> 55#include <gui/Surface.h> 56 57#include <media/stagefright/foundation/AMessage.h> 58 59#include <cutils/properties.h> 60 61#define USE_SURFACE_ALLOC 1 62#define FRAME_DROP_FREQ 0 63 64namespace android { 65 66static int64_t kLowWaterMarkUs = 2000000ll; // 2secs 67static int64_t kHighWaterMarkUs = 5000000ll; // 5secs 68static const size_t kLowWaterMarkBytes = 40000; 69static const size_t kHighWaterMarkBytes = 200000; 70 71// maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer 72// is destroyed to allow the audio DSP to power down. 73static int64_t kOffloadPauseMaxUs = 60000000ll; 74 75 76struct AwesomeEvent : public TimedEventQueue::Event { 77 AwesomeEvent( 78 AwesomePlayer *player, 79 void (AwesomePlayer::*method)()) 80 : mPlayer(player), 81 mMethod(method) { 82 } 83 84protected: 85 virtual ~AwesomeEvent() {} 86 87 virtual void fire(TimedEventQueue * /* queue */, int64_t /* now_us */) { 88 (mPlayer->*mMethod)(); 89 } 90 91private: 92 AwesomePlayer *mPlayer; 93 void (AwesomePlayer::*mMethod)(); 94 95 AwesomeEvent(const AwesomeEvent &); 96 AwesomeEvent &operator=(const AwesomeEvent &); 97}; 98 99struct AwesomeLocalRenderer : public AwesomeRenderer { 100 AwesomeLocalRenderer( 101 const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta) 102 : mTarget(new SoftwareRenderer(nativeWindow, meta)) { 103 } 104 105 virtual void render(MediaBuffer *buffer) { 106 render((const uint8_t *)buffer->data() + buffer->range_offset(), 107 buffer->range_length()); 108 } 109 110 void render(const void *data, size_t size) { 111 mTarget->render(data, size, NULL); 112 } 113 114protected: 115 virtual ~AwesomeLocalRenderer() { 116 delete mTarget; 117 mTarget = NULL; 118 } 119 120private: 121 SoftwareRenderer *mTarget; 122 123 AwesomeLocalRenderer(const AwesomeLocalRenderer &); 124 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);; 125}; 126 127struct AwesomeNativeWindowRenderer : public AwesomeRenderer { 128 AwesomeNativeWindowRenderer( 129 const sp<ANativeWindow> &nativeWindow, 130 int32_t rotationDegrees) 131 : mNativeWindow(nativeWindow) { 132 applyRotation(rotationDegrees); 133 } 134 135 virtual void render(MediaBuffer *buffer) { 136 ATRACE_CALL(); 137 int64_t timeUs; 138 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); 139 native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000); 140 status_t err = mNativeWindow->queueBuffer( 141 mNativeWindow.get(), buffer->graphicBuffer().get(), -1); 142 if (err != 0) { 143 ALOGE("queueBuffer failed with error %s (%d)", strerror(-err), 144 -err); 145 return; 146 } 147 148 sp<MetaData> metaData = buffer->meta_data(); 149 metaData->setInt32(kKeyRendered, 1); 150 } 151 152protected: 153 virtual ~AwesomeNativeWindowRenderer() {} 154 155private: 156 sp<ANativeWindow> mNativeWindow; 157 158 void applyRotation(int32_t rotationDegrees) { 159 uint32_t transform; 160 switch (rotationDegrees) { 161 case 0: transform = 0; break; 162 case 90: transform = HAL_TRANSFORM_ROT_90; break; 163 case 180: transform = HAL_TRANSFORM_ROT_180; break; 164 case 270: transform = HAL_TRANSFORM_ROT_270; break; 165 default: transform = 0; break; 166 } 167 168 if (transform) { 169 CHECK_EQ(0, native_window_set_buffers_transform( 170 mNativeWindow.get(), transform)); 171 } 172 } 173 174 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &); 175 AwesomeNativeWindowRenderer &operator=( 176 const AwesomeNativeWindowRenderer &); 177}; 178 179// To collect the decoder usage 180void addBatteryData(uint32_t params) { 181 sp<IBinder> binder = 182 defaultServiceManager()->getService(String16("media.player")); 183 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 184 CHECK(service.get() != NULL); 185 186 service->addBatteryData(params); 187} 188 189//////////////////////////////////////////////////////////////////////////////// 190AwesomePlayer::AwesomePlayer() 191 : mQueueStarted(false), 192 mUIDValid(false), 193 mTimeSource(NULL), 194 mVideoRenderingStarted(false), 195 mVideoRendererIsPreview(false), 196 mMediaRenderingStartGeneration(0), 197 mStartGeneration(0), 198 mAudioPlayer(NULL), 199 mDisplayWidth(0), 200 mDisplayHeight(0), 201 mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW), 202 mFlags(0), 203 mExtractorFlags(0), 204 mVideoBuffer(NULL), 205 mDecryptHandle(NULL), 206 mLastVideoTimeUs(-1), 207 mTextDriver(NULL), 208 mOffloadAudio(false), 209 mAudioTearDown(false) { 210 CHECK_EQ(mClient.connect(), (status_t)OK); 211 212 DataSource::RegisterDefaultSniffers(); 213 214 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); 215 mVideoEventPending = false; 216 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone); 217 mStreamDoneEventPending = false; 218 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate); 219 mBufferingEventPending = false; 220 mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate); 221 mVideoLagEventPending = false; 222 223 mCheckAudioStatusEvent = new AwesomeEvent( 224 this, &AwesomePlayer::onCheckAudioStatus); 225 226 mAudioStatusEventPending = false; 227 228 mAudioTearDownEvent = new AwesomeEvent(this, 229 &AwesomePlayer::onAudioTearDownEvent); 230 mAudioTearDownEventPending = false; 231 232 mClockEstimator = new WindowedLinearFitEstimator(); 233 234 reset(); 235} 236 237AwesomePlayer::~AwesomePlayer() { 238 if (mQueueStarted) { 239 mQueue.stop(); 240 } 241 242 reset(); 243 244 mClient.disconnect(); 245} 246 247void AwesomePlayer::cancelPlayerEvents(bool keepNotifications) { 248 mQueue.cancelEvent(mVideoEvent->eventID()); 249 mVideoEventPending = false; 250 mQueue.cancelEvent(mVideoLagEvent->eventID()); 251 mVideoLagEventPending = false; 252 253 if (mOffloadAudio) { 254 mQueue.cancelEvent(mAudioTearDownEvent->eventID()); 255 mAudioTearDownEventPending = false; 256 } 257 258 if (!keepNotifications) { 259 mQueue.cancelEvent(mStreamDoneEvent->eventID()); 260 mStreamDoneEventPending = false; 261 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID()); 262 mAudioStatusEventPending = false; 263 264 mQueue.cancelEvent(mBufferingEvent->eventID()); 265 mBufferingEventPending = false; 266 mAudioTearDown = false; 267 } 268} 269 270void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) { 271 Mutex::Autolock autoLock(mLock); 272 mListener = listener; 273} 274 275void AwesomePlayer::setUID(uid_t uid) { 276 ALOGV("AwesomePlayer running on behalf of uid %d", uid); 277 278 mUID = uid; 279 mUIDValid = true; 280} 281 282status_t AwesomePlayer::setDataSource( 283 const char *uri, const KeyedVector<String8, String8> *headers) { 284 Mutex::Autolock autoLock(mLock); 285 return setDataSource_l(uri, headers); 286} 287 288status_t AwesomePlayer::setDataSource_l( 289 const char *uri, const KeyedVector<String8, String8> *headers) { 290 reset_l(); 291 292 mUri = uri; 293 294 if (headers) { 295 mUriHeaders = *headers; 296 297 ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log")); 298 if (index >= 0) { 299 // Browser is in "incognito" mode, suppress logging URLs. 300 301 // This isn't something that should be passed to the server. 302 mUriHeaders.removeItemsAt(index); 303 304 modifyFlags(INCOGNITO, SET); 305 } 306 } 307 308 ALOGI("setDataSource_l(URL suppressed)"); 309 310 // The actual work will be done during preparation in the call to 311 // ::finishSetDataSource_l to avoid blocking the calling thread in 312 // setDataSource for any significant time. 313 314 { 315 Mutex::Autolock autoLock(mStatsLock); 316 mStats.mFd = -1; 317 mStats.mURI = mUri; 318 } 319 320 return OK; 321} 322 323status_t AwesomePlayer::setDataSource( 324 int fd, int64_t offset, int64_t length) { 325 Mutex::Autolock autoLock(mLock); 326 327 reset_l(); 328 329 sp<DataSource> dataSource = new FileSource(fd, offset, length); 330 331 status_t err = dataSource->initCheck(); 332 333 if (err != OK) { 334 return err; 335 } 336 337 mFileSource = dataSource; 338 339 { 340 Mutex::Autolock autoLock(mStatsLock); 341 mStats.mFd = fd; 342 mStats.mURI = String8(); 343 } 344 345 return setDataSource_l(dataSource); 346} 347 348status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) { 349 return INVALID_OPERATION; 350} 351 352status_t AwesomePlayer::setDataSource_l( 353 const sp<DataSource> &dataSource) { 354 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 355 356 if (extractor == NULL) { 357 return UNKNOWN_ERROR; 358 } 359 360 if (extractor->getDrmFlag()) { 361 checkDrmStatus(dataSource); 362 } 363 364 return setDataSource_l(extractor); 365} 366 367void AwesomePlayer::checkDrmStatus(const sp<DataSource>& dataSource) { 368 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 369 if (mDecryptHandle != NULL) { 370 CHECK(mDrmManagerClient); 371 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 372 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); 373 } 374 } 375} 376 377status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { 378 // Attempt to approximate overall stream bitrate by summing all 379 // tracks' individual bitrates, if not all of them advertise bitrate, 380 // we have to fail. 381 382 int64_t totalBitRate = 0; 383 384 mExtractor = extractor; 385 for (size_t i = 0; i < extractor->countTracks(); ++i) { 386 sp<MetaData> meta = extractor->getTrackMetaData(i); 387 388 int32_t bitrate; 389 if (!meta->findInt32(kKeyBitRate, &bitrate)) { 390 const char *mime; 391 CHECK(meta->findCString(kKeyMIMEType, &mime)); 392 ALOGV("track of type '%s' does not publish bitrate", mime); 393 394 totalBitRate = -1; 395 break; 396 } 397 398 totalBitRate += bitrate; 399 } 400 401 mBitrate = totalBitRate; 402 403 ALOGV("mBitrate = %lld bits/sec", mBitrate); 404 405 { 406 Mutex::Autolock autoLock(mStatsLock); 407 mStats.mBitrate = mBitrate; 408 mStats.mTracks.clear(); 409 mStats.mAudioTrackIndex = -1; 410 mStats.mVideoTrackIndex = -1; 411 } 412 413 bool haveAudio = false; 414 bool haveVideo = false; 415 for (size_t i = 0; i < extractor->countTracks(); ++i) { 416 sp<MetaData> meta = extractor->getTrackMetaData(i); 417 418 const char *_mime; 419 CHECK(meta->findCString(kKeyMIMEType, &_mime)); 420 421 String8 mime = String8(_mime); 422 423 if (!haveVideo && !strncasecmp(mime.string(), "video/", 6)) { 424 setVideoSource(extractor->getTrack(i)); 425 haveVideo = true; 426 427 // Set the presentation/display size 428 int32_t displayWidth, displayHeight; 429 bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth); 430 if (success) { 431 success = meta->findInt32(kKeyDisplayHeight, &displayHeight); 432 } 433 if (success) { 434 mDisplayWidth = displayWidth; 435 mDisplayHeight = displayHeight; 436 } 437 438 { 439 Mutex::Autolock autoLock(mStatsLock); 440 mStats.mVideoTrackIndex = mStats.mTracks.size(); 441 mStats.mTracks.push(); 442 TrackStat *stat = 443 &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 444 stat->mMIME = mime.string(); 445 } 446 } else if (!haveAudio && !strncasecmp(mime.string(), "audio/", 6)) { 447 setAudioSource(extractor->getTrack(i)); 448 haveAudio = true; 449 mActiveAudioTrackIndex = i; 450 451 { 452 Mutex::Autolock autoLock(mStatsLock); 453 mStats.mAudioTrackIndex = mStats.mTracks.size(); 454 mStats.mTracks.push(); 455 TrackStat *stat = 456 &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 457 stat->mMIME = mime.string(); 458 } 459 460 if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_AUDIO_VORBIS)) { 461 // Only do this for vorbis audio, none of the other audio 462 // formats even support this ringtone specific hack and 463 // retrieving the metadata on some extractors may turn out 464 // to be very expensive. 465 sp<MetaData> fileMeta = extractor->getMetaData(); 466 int32_t loop; 467 if (fileMeta != NULL 468 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 469 modifyFlags(AUTO_LOOPING, SET); 470 } 471 } 472 } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { 473 addTextSource_l(i, extractor->getTrack(i)); 474 } 475 } 476 477 if (!haveAudio && !haveVideo) { 478 if (mWVMExtractor != NULL) { 479 return mWVMExtractor->getError(); 480 } else { 481 return UNKNOWN_ERROR; 482 } 483 } 484 485 mExtractorFlags = extractor->flags(); 486 487 return OK; 488} 489 490void AwesomePlayer::reset() { 491 Mutex::Autolock autoLock(mLock); 492 reset_l(); 493} 494 495void AwesomePlayer::reset_l() { 496 mVideoRenderingStarted = false; 497 mActiveAudioTrackIndex = -1; 498 mDisplayWidth = 0; 499 mDisplayHeight = 0; 500 501 notifyListener_l(MEDIA_STOPPED); 502 503 if (mDecryptHandle != NULL) { 504 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 505 Playback::STOP, 0); 506 mDecryptHandle = NULL; 507 mDrmManagerClient = NULL; 508 } 509 510 if (mFlags & PLAYING) { 511 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 512 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 513 params |= IMediaPlayerService::kBatteryDataTrackAudio; 514 } 515 if (mVideoSource != NULL) { 516 params |= IMediaPlayerService::kBatteryDataTrackVideo; 517 } 518 addBatteryData(params); 519 } 520 521 if (mFlags & PREPARING) { 522 modifyFlags(PREPARE_CANCELLED, SET); 523 if (mConnectingDataSource != NULL) { 524 ALOGI("interrupting the connection process"); 525 mConnectingDataSource->disconnect(); 526 } 527 528 if (mFlags & PREPARING_CONNECTED) { 529 // We are basically done preparing, we're just buffering 530 // enough data to start playback, we can safely interrupt that. 531 finishAsyncPrepare_l(); 532 } 533 } 534 535 while (mFlags & PREPARING) { 536 mPreparedCondition.wait(mLock); 537 } 538 539 cancelPlayerEvents(); 540 541 mWVMExtractor.clear(); 542 mCachedSource.clear(); 543 mAudioTrack.clear(); 544 mVideoTrack.clear(); 545 mExtractor.clear(); 546 547 // Shutdown audio first, so that the response to the reset request 548 // appears to happen instantaneously as far as the user is concerned 549 // If we did this later, audio would continue playing while we 550 // shutdown the video-related resources and the player appear to 551 // not be as responsive to a reset request. 552 if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED)) 553 && mAudioSource != NULL) { 554 // If we had an audio player, it would have effectively 555 // taken possession of the audio source and stopped it when 556 // _it_ is stopped. Otherwise this is still our responsibility. 557 mAudioSource->stop(); 558 } 559 mAudioSource.clear(); 560 mOmxSource.clear(); 561 562 mTimeSource = NULL; 563 564 delete mAudioPlayer; 565 mAudioPlayer = NULL; 566 567 if (mTextDriver != NULL) { 568 delete mTextDriver; 569 mTextDriver = NULL; 570 } 571 572 mVideoRenderer.clear(); 573 574 if (mVideoSource != NULL) { 575 shutdownVideoDecoder_l(); 576 } 577 578 mDurationUs = -1; 579 modifyFlags(0, ASSIGN); 580 mExtractorFlags = 0; 581 mTimeSourceDeltaUs = 0; 582 mVideoTimeUs = 0; 583 584 mSeeking = NO_SEEK; 585 mSeekNotificationSent = true; 586 mSeekTimeUs = 0; 587 588 mUri.setTo(""); 589 mUriHeaders.clear(); 590 591 mFileSource.clear(); 592 593 mBitrate = -1; 594 mLastVideoTimeUs = -1; 595 596 { 597 Mutex::Autolock autoLock(mStatsLock); 598 mStats.mFd = -1; 599 mStats.mURI = String8(); 600 mStats.mBitrate = -1; 601 mStats.mAudioTrackIndex = -1; 602 mStats.mVideoTrackIndex = -1; 603 mStats.mNumVideoFramesDecoded = 0; 604 mStats.mNumVideoFramesDropped = 0; 605 mStats.mVideoWidth = -1; 606 mStats.mVideoHeight = -1; 607 mStats.mFlags = 0; 608 mStats.mTracks.clear(); 609 } 610 611 mWatchForAudioSeekComplete = false; 612 mWatchForAudioEOS = false; 613 614 mMediaRenderingStartGeneration = 0; 615 mStartGeneration = 0; 616} 617 618void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { 619 if ((mListener != NULL) && !mAudioTearDown) { 620 sp<MediaPlayerBase> listener = mListener.promote(); 621 622 if (listener != NULL) { 623 listener->sendEvent(msg, ext1, ext2); 624 } 625 } 626} 627 628bool AwesomePlayer::getBitrate(int64_t *bitrate) { 629 off64_t size; 630 if (mDurationUs > 0 && mCachedSource != NULL 631 && mCachedSource->getSize(&size) == OK) { 632 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec 633 return true; 634 } 635 636 if (mBitrate >= 0) { 637 *bitrate = mBitrate; 638 return true; 639 } 640 641 *bitrate = 0; 642 643 return false; 644} 645 646// Returns true iff cached duration is available/applicable. 647bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { 648 int64_t bitrate; 649 650 if (mCachedSource != NULL && getBitrate(&bitrate) && (bitrate > 0)) { 651 status_t finalStatus; 652 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 653 *durationUs = cachedDataRemaining * 8000000ll / bitrate; 654 *eos = (finalStatus != OK); 655 return true; 656 } else if (mWVMExtractor != NULL) { 657 status_t finalStatus; 658 *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); 659 *eos = (finalStatus != OK); 660 return true; 661 } 662 663 return false; 664} 665 666void AwesomePlayer::ensureCacheIsFetching_l() { 667 if (mCachedSource != NULL) { 668 mCachedSource->resumeFetchingIfNecessary(); 669 } 670} 671 672void AwesomePlayer::onVideoLagUpdate() { 673 Mutex::Autolock autoLock(mLock); 674 if (!mVideoLagEventPending) { 675 return; 676 } 677 mVideoLagEventPending = false; 678 679 int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs(); 680 int64_t videoLateByUs = audioTimeUs - mVideoTimeUs; 681 682 if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) { 683 ALOGV("video late by %lld ms.", videoLateByUs / 1000ll); 684 685 notifyListener_l( 686 MEDIA_INFO, 687 MEDIA_INFO_VIDEO_TRACK_LAGGING, 688 videoLateByUs / 1000ll); 689 } 690 691 postVideoLagEvent_l(); 692} 693 694void AwesomePlayer::onBufferingUpdate() { 695 Mutex::Autolock autoLock(mLock); 696 if (!mBufferingEventPending) { 697 return; 698 } 699 mBufferingEventPending = false; 700 701 if (mCachedSource != NULL) { 702 status_t finalStatus; 703 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 704 bool eos = (finalStatus != OK); 705 706 if (eos) { 707 if (finalStatus == ERROR_END_OF_STREAM) { 708 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 709 } 710 if (mFlags & PREPARING) { 711 ALOGV("cache has reached EOS, prepare is done."); 712 finishAsyncPrepare_l(); 713 } 714 } else { 715 int64_t bitrate; 716 if (getBitrate(&bitrate)) { 717 size_t cachedSize = mCachedSource->cachedSize(); 718 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; 719 720 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 721 if (percentage > 100) { 722 percentage = 100; 723 } 724 725 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 726 } else { 727 // We don't know the bitrate of the stream, use absolute size 728 // limits to maintain the cache. 729 730 if ((mFlags & PLAYING) && !eos 731 && (cachedDataRemaining < kLowWaterMarkBytes)) { 732 ALOGI("cache is running low (< %zu) , pausing.", 733 kLowWaterMarkBytes); 734 modifyFlags(CACHE_UNDERRUN, SET); 735 pause_l(); 736 ensureCacheIsFetching_l(); 737 sendCacheStats(); 738 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 739 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { 740 if (mFlags & CACHE_UNDERRUN) { 741 ALOGI("cache has filled up (> %zu), resuming.", 742 kHighWaterMarkBytes); 743 modifyFlags(CACHE_UNDERRUN, CLEAR); 744 play_l(); 745 } else if (mFlags & PREPARING) { 746 ALOGV("cache has filled up (> %zu), prepare is done", 747 kHighWaterMarkBytes); 748 finishAsyncPrepare_l(); 749 } 750 } 751 } 752 } 753 } else if (mWVMExtractor != NULL) { 754 status_t finalStatus; 755 756 int64_t cachedDurationUs 757 = mWVMExtractor->getCachedDurationUs(&finalStatus); 758 759 bool eos = (finalStatus != OK); 760 761 if (eos) { 762 if (finalStatus == ERROR_END_OF_STREAM) { 763 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 764 } 765 if (mFlags & PREPARING) { 766 ALOGV("cache has reached EOS, prepare is done."); 767 finishAsyncPrepare_l(); 768 } 769 } else { 770 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 771 if (percentage > 100) { 772 percentage = 100; 773 } 774 775 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 776 } 777 } 778 779 int64_t cachedDurationUs; 780 bool eos; 781 if (getCachedDuration_l(&cachedDurationUs, &eos)) { 782 ALOGV("cachedDurationUs = %.2f secs, eos=%d", 783 cachedDurationUs / 1E6, eos); 784 785 if ((mFlags & PLAYING) && !eos 786 && (cachedDurationUs < kLowWaterMarkUs)) { 787 modifyFlags(CACHE_UNDERRUN, SET); 788 ALOGI("cache is running low (%.2f secs) , pausing.", 789 cachedDurationUs / 1E6); 790 pause_l(); 791 ensureCacheIsFetching_l(); 792 sendCacheStats(); 793 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 794 } else if (eos || cachedDurationUs > kHighWaterMarkUs) { 795 if (mFlags & CACHE_UNDERRUN) { 796 modifyFlags(CACHE_UNDERRUN, CLEAR); 797 ALOGI("cache has filled up (%.2f secs), resuming.", 798 cachedDurationUs / 1E6); 799 play_l(); 800 } else if (mFlags & PREPARING) { 801 ALOGV("cache has filled up (%.2f secs), prepare is done", 802 cachedDurationUs / 1E6); 803 finishAsyncPrepare_l(); 804 } 805 } 806 } 807 808 if (mFlags & (PLAYING | PREPARING | CACHE_UNDERRUN)) { 809 postBufferingEvent_l(); 810 } 811} 812 813void AwesomePlayer::sendCacheStats() { 814 sp<MediaPlayerBase> listener = mListener.promote(); 815 if (listener != NULL) { 816 int32_t kbps = 0; 817 status_t err = UNKNOWN_ERROR; 818 if (mCachedSource != NULL) { 819 err = mCachedSource->getEstimatedBandwidthKbps(&kbps); 820 } else if (mWVMExtractor != NULL) { 821 err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps); 822 } 823 if (err == OK) { 824 listener->sendEvent( 825 MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps); 826 } 827 } 828} 829 830void AwesomePlayer::onStreamDone() { 831 // Posted whenever any stream finishes playing. 832 ATRACE_CALL(); 833 834 Mutex::Autolock autoLock(mLock); 835 if (!mStreamDoneEventPending) { 836 return; 837 } 838 mStreamDoneEventPending = false; 839 840 if (mStreamDoneStatus != ERROR_END_OF_STREAM) { 841 ALOGV("MEDIA_ERROR %d", mStreamDoneStatus); 842 843 notifyListener_l( 844 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus); 845 846 pause_l(true /* at eos */); 847 848 modifyFlags(AT_EOS, SET); 849 return; 850 } 851 852 const bool allDone = 853 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS)) 854 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS)); 855 856 if (!allDone) { 857 return; 858 } 859 860 if ((mFlags & LOOPING) 861 || ((mFlags & AUTO_LOOPING) 862 && (mAudioSink == NULL || mAudioSink->realtime()))) { 863 // Don't AUTO_LOOP if we're being recorded, since that cannot be 864 // turned off and recording would go on indefinitely. 865 866 seekTo_l(0); 867 868 if (mVideoSource != NULL) { 869 postVideoEvent_l(); 870 } 871 } else { 872 ALOGV("MEDIA_PLAYBACK_COMPLETE"); 873 notifyListener_l(MEDIA_PLAYBACK_COMPLETE); 874 875 pause_l(true /* at eos */); 876 877 // If audio hasn't completed MEDIA_SEEK_COMPLETE yet, 878 // notify MEDIA_SEEK_COMPLETE to observer immediately for state persistence. 879 if (mWatchForAudioSeekComplete) { 880 notifyListener_l(MEDIA_SEEK_COMPLETE); 881 mWatchForAudioSeekComplete = false; 882 } 883 884 modifyFlags(AT_EOS, SET); 885 } 886} 887 888status_t AwesomePlayer::play() { 889 ATRACE_CALL(); 890 891 Mutex::Autolock autoLock(mLock); 892 893 modifyFlags(CACHE_UNDERRUN, CLEAR); 894 895 return play_l(); 896} 897 898status_t AwesomePlayer::play_l() { 899 modifyFlags(SEEK_PREVIEW, CLEAR); 900 901 if (mFlags & PLAYING) { 902 return OK; 903 } 904 905 mMediaRenderingStartGeneration = ++mStartGeneration; 906 907 if (!(mFlags & PREPARED)) { 908 status_t err = prepare_l(); 909 910 if (err != OK) { 911 return err; 912 } 913 } 914 915 modifyFlags(PLAYING, SET); 916 modifyFlags(FIRST_FRAME, SET); 917 918 if (mDecryptHandle != NULL) { 919 int64_t position; 920 getPosition(&position); 921 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 922 Playback::START, position / 1000); 923 } 924 925 if (mAudioSource != NULL) { 926 if (mAudioPlayer == NULL) { 927 createAudioPlayer_l(); 928 } 929 930 CHECK(!(mFlags & AUDIO_RUNNING)); 931 932 if (mVideoSource == NULL) { 933 934 // We don't want to post an error notification at this point, 935 // the error returned from MediaPlayer::start() will suffice. 936 937 status_t err = startAudioPlayer_l( 938 false /* sendErrorNotification */); 939 940 if ((err != OK) && mOffloadAudio) { 941 ALOGI("play_l() cannot create offload output, fallback to sw decode"); 942 int64_t curTimeUs; 943 getPosition(&curTimeUs); 944 945 delete mAudioPlayer; 946 mAudioPlayer = NULL; 947 // if the player was started it will take care of stopping the source when destroyed 948 if (!(mFlags & AUDIOPLAYER_STARTED)) { 949 mAudioSource->stop(); 950 } 951 modifyFlags((AUDIO_RUNNING | AUDIOPLAYER_STARTED), CLEAR); 952 mOffloadAudio = false; 953 mAudioSource = mOmxSource; 954 if (mAudioSource != NULL) { 955 err = mAudioSource->start(); 956 957 if (err != OK) { 958 mAudioSource.clear(); 959 } else { 960 mSeekNotificationSent = true; 961 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 962 seekTo_l(curTimeUs); 963 } 964 createAudioPlayer_l(); 965 err = startAudioPlayer_l(false); 966 } 967 } 968 } 969 970 if (err != OK) { 971 delete mAudioPlayer; 972 mAudioPlayer = NULL; 973 974 modifyFlags((PLAYING | FIRST_FRAME), CLEAR); 975 976 if (mDecryptHandle != NULL) { 977 mDrmManagerClient->setPlaybackStatus( 978 mDecryptHandle, Playback::STOP, 0); 979 } 980 981 return err; 982 } 983 } 984 } 985 986 if (mTimeSource == NULL && mAudioPlayer == NULL) { 987 mTimeSource = &mSystemTimeSource; 988 } 989 990 if (mVideoSource != NULL) { 991 // Kick off video playback 992 postVideoEvent_l(); 993 994 if (mAudioSource != NULL && mVideoSource != NULL) { 995 postVideoLagEvent_l(); 996 } 997 } 998 999 if (mFlags & AT_EOS) { 1000 // Legacy behaviour, if a stream finishes playing and then 1001 // is started again, we play from the start... 1002 seekTo_l(0); 1003 } 1004 1005 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted 1006 | IMediaPlayerService::kBatteryDataTrackDecoder; 1007 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 1008 params |= IMediaPlayerService::kBatteryDataTrackAudio; 1009 } 1010 if (mVideoSource != NULL) { 1011 params |= IMediaPlayerService::kBatteryDataTrackVideo; 1012 } 1013 addBatteryData(params); 1014 1015 if (isStreamingHTTP()) { 1016 postBufferingEvent_l(); 1017 } 1018 1019 return OK; 1020} 1021 1022void AwesomePlayer::createAudioPlayer_l() 1023{ 1024 uint32_t flags = 0; 1025 int64_t cachedDurationUs; 1026 bool eos; 1027 1028 if (mOffloadAudio) { 1029 flags |= AudioPlayer::USE_OFFLOAD; 1030 } else if (mVideoSource == NULL 1031 && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US || 1032 (getCachedDuration_l(&cachedDurationUs, &eos) && 1033 cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) { 1034 flags |= AudioPlayer::ALLOW_DEEP_BUFFERING; 1035 } 1036 if (isStreamingHTTP()) { 1037 flags |= AudioPlayer::IS_STREAMING; 1038 } 1039 if (mVideoSource != NULL) { 1040 flags |= AudioPlayer::HAS_VIDEO; 1041 } 1042 1043 mAudioPlayer = new AudioPlayer(mAudioSink, flags, this); 1044 mAudioPlayer->setSource(mAudioSource); 1045 1046 mTimeSource = mAudioPlayer; 1047 1048 // If there was a seek request before we ever started, 1049 // honor the request now. 1050 // Make sure to do this before starting the audio player 1051 // to avoid a race condition. 1052 seekAudioIfNecessary_l(); 1053} 1054 1055void AwesomePlayer::notifyIfMediaStarted_l() { 1056 if (mMediaRenderingStartGeneration == mStartGeneration) { 1057 mMediaRenderingStartGeneration = -1; 1058 notifyListener_l(MEDIA_STARTED); 1059 } 1060} 1061 1062status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) { 1063 CHECK(!(mFlags & AUDIO_RUNNING)); 1064 status_t err = OK; 1065 1066 if (mAudioSource == NULL || mAudioPlayer == NULL) { 1067 return OK; 1068 } 1069 1070 if (mOffloadAudio) { 1071 mQueue.cancelEvent(mAudioTearDownEvent->eventID()); 1072 mAudioTearDownEventPending = false; 1073 } 1074 1075 if (!(mFlags & AUDIOPLAYER_STARTED)) { 1076 bool wasSeeking = mAudioPlayer->isSeeking(); 1077 1078 // We've already started the MediaSource in order to enable 1079 // the prefetcher to read its data. 1080 err = mAudioPlayer->start( 1081 true /* sourceAlreadyStarted */); 1082 1083 if (err != OK) { 1084 if (sendErrorNotification) { 1085 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 1086 } 1087 1088 return err; 1089 } 1090 1091 modifyFlags(AUDIOPLAYER_STARTED, SET); 1092 1093 if (wasSeeking) { 1094 CHECK(!mAudioPlayer->isSeeking()); 1095 1096 // We will have finished the seek while starting the audio player. 1097 postAudioSeekComplete(); 1098 } else { 1099 notifyIfMediaStarted_l(); 1100 } 1101 } else { 1102 err = mAudioPlayer->resume(); 1103 } 1104 1105 if (err == OK) { 1106 modifyFlags(AUDIO_RUNNING, SET); 1107 1108 mWatchForAudioEOS = true; 1109 } 1110 1111 return err; 1112} 1113 1114void AwesomePlayer::notifyVideoSize_l() { 1115 ATRACE_CALL(); 1116 sp<MetaData> meta = mVideoSource->getFormat(); 1117 1118 int32_t cropLeft, cropTop, cropRight, cropBottom; 1119 if (!meta->findRect( 1120 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) { 1121 int32_t width, height; 1122 CHECK(meta->findInt32(kKeyWidth, &width)); 1123 CHECK(meta->findInt32(kKeyHeight, &height)); 1124 1125 cropLeft = cropTop = 0; 1126 cropRight = width - 1; 1127 cropBottom = height - 1; 1128 1129 ALOGV("got dimensions only %d x %d", width, height); 1130 } else { 1131 ALOGV("got crop rect %d, %d, %d, %d", 1132 cropLeft, cropTop, cropRight, cropBottom); 1133 } 1134 1135 int32_t displayWidth; 1136 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) { 1137 ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth); 1138 mDisplayWidth = displayWidth; 1139 } 1140 int32_t displayHeight; 1141 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) { 1142 ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight); 1143 mDisplayHeight = displayHeight; 1144 } 1145 1146 int32_t usableWidth = cropRight - cropLeft + 1; 1147 int32_t usableHeight = cropBottom - cropTop + 1; 1148 if (mDisplayWidth != 0) { 1149 usableWidth = mDisplayWidth; 1150 } 1151 if (mDisplayHeight != 0) { 1152 usableHeight = mDisplayHeight; 1153 } 1154 1155 { 1156 Mutex::Autolock autoLock(mStatsLock); 1157 mStats.mVideoWidth = usableWidth; 1158 mStats.mVideoHeight = usableHeight; 1159 } 1160 1161 int32_t rotationDegrees; 1162 if (!mVideoTrack->getFormat()->findInt32( 1163 kKeyRotation, &rotationDegrees)) { 1164 rotationDegrees = 0; 1165 } 1166 1167 if (rotationDegrees == 90 || rotationDegrees == 270) { 1168 notifyListener_l( 1169 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth); 1170 } else { 1171 notifyListener_l( 1172 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight); 1173 } 1174} 1175 1176void AwesomePlayer::initRenderer_l() { 1177 ATRACE_CALL(); 1178 1179 if (mNativeWindow == NULL) { 1180 return; 1181 } 1182 1183 sp<MetaData> meta = mVideoSource->getFormat(); 1184 1185 int32_t format; 1186 const char *component; 1187 int32_t decodedWidth, decodedHeight; 1188 CHECK(meta->findInt32(kKeyColorFormat, &format)); 1189 CHECK(meta->findCString(kKeyDecoderComponent, &component)); 1190 CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); 1191 CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); 1192 1193 int32_t rotationDegrees; 1194 if (!mVideoTrack->getFormat()->findInt32( 1195 kKeyRotation, &rotationDegrees)) { 1196 rotationDegrees = 0; 1197 } 1198 1199 mVideoRenderer.clear(); 1200 1201 // Must ensure that mVideoRenderer's destructor is actually executed 1202 // before creating a new one. 1203 IPCThreadState::self()->flushCommands(); 1204 1205 // Even if set scaling mode fails, we will continue anyway 1206 setVideoScalingMode_l(mVideoScalingMode); 1207 if (USE_SURFACE_ALLOC 1208 && !strncmp(component, "OMX.", 4) 1209 && strncmp(component, "OMX.google.", 11)) { 1210 // Hardware decoders avoid the CPU color conversion by decoding 1211 // directly to ANativeBuffers, so we must use a renderer that 1212 // just pushes those buffers to the ANativeWindow. 1213 mVideoRenderer = 1214 new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees); 1215 } else { 1216 // Other decoders are instantiated locally and as a consequence 1217 // allocate their buffers in local address space. This renderer 1218 // then performs a color conversion and copy to get the data 1219 // into the ANativeBuffer. 1220 mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta); 1221 } 1222} 1223 1224status_t AwesomePlayer::pause() { 1225 ATRACE_CALL(); 1226 1227 Mutex::Autolock autoLock(mLock); 1228 1229 modifyFlags(CACHE_UNDERRUN, CLEAR); 1230 1231 return pause_l(); 1232} 1233 1234status_t AwesomePlayer::pause_l(bool at_eos) { 1235 if (!(mFlags & PLAYING)) { 1236 if (mAudioTearDown && mAudioTearDownWasPlaying) { 1237 ALOGV("pause_l() during teardown and finishSetDataSource_l() mFlags %x" , mFlags); 1238 mAudioTearDownWasPlaying = false; 1239 notifyListener_l(MEDIA_PAUSED); 1240 mMediaRenderingStartGeneration = ++mStartGeneration; 1241 } 1242 return OK; 1243 } 1244 1245 notifyListener_l(MEDIA_PAUSED); 1246 mMediaRenderingStartGeneration = ++mStartGeneration; 1247 1248 cancelPlayerEvents(true /* keepNotifications */); 1249 1250 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1251 // If we played the audio stream to completion we 1252 // want to make sure that all samples remaining in the audio 1253 // track's queue are played out. 1254 mAudioPlayer->pause(at_eos /* playPendingSamples */); 1255 // send us a reminder to tear down the AudioPlayer if paused for too long. 1256 if (mOffloadAudio) { 1257 postAudioTearDownEvent(kOffloadPauseMaxUs); 1258 } 1259 modifyFlags(AUDIO_RUNNING, CLEAR); 1260 } 1261 1262 if (mFlags & TEXTPLAYER_INITIALIZED) { 1263 mTextDriver->pause(); 1264 modifyFlags(TEXT_RUNNING, CLEAR); 1265 } 1266 1267 modifyFlags(PLAYING, CLEAR); 1268 1269 if (mDecryptHandle != NULL) { 1270 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1271 Playback::PAUSE, 0); 1272 } 1273 1274 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 1275 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 1276 params |= IMediaPlayerService::kBatteryDataTrackAudio; 1277 } 1278 if (mVideoSource != NULL) { 1279 params |= IMediaPlayerService::kBatteryDataTrackVideo; 1280 } 1281 1282 addBatteryData(params); 1283 1284 return OK; 1285} 1286 1287bool AwesomePlayer::isPlaying() const { 1288 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN); 1289} 1290 1291status_t AwesomePlayer::setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) { 1292 Mutex::Autolock autoLock(mLock); 1293 1294 status_t err; 1295 if (bufferProducer != NULL) { 1296 err = setNativeWindow_l(new Surface(bufferProducer)); 1297 } else { 1298 err = setNativeWindow_l(NULL); 1299 } 1300 1301 return err; 1302} 1303 1304void AwesomePlayer::shutdownVideoDecoder_l() { 1305 if (mVideoBuffer) { 1306 mVideoBuffer->release(); 1307 mVideoBuffer = NULL; 1308 } 1309 1310 mVideoSource->stop(); 1311 1312 // The following hack is necessary to ensure that the OMX 1313 // component is completely released by the time we may try 1314 // to instantiate it again. 1315 wp<MediaSource> tmp = mVideoSource; 1316 mVideoSource.clear(); 1317 while (tmp.promote() != NULL) { 1318 usleep(1000); 1319 } 1320 IPCThreadState::self()->flushCommands(); 1321 ALOGV("video decoder shutdown completed"); 1322} 1323 1324status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) { 1325 mNativeWindow = native; 1326 1327 if (mVideoSource == NULL) { 1328 return OK; 1329 } 1330 1331 ALOGV("attempting to reconfigure to use new surface"); 1332 1333 bool wasPlaying = (mFlags & PLAYING) != 0; 1334 1335 pause_l(); 1336 mVideoRenderer.clear(); 1337 1338 shutdownVideoDecoder_l(); 1339 1340 status_t err = initVideoDecoder(); 1341 1342 if (err != OK) { 1343 ALOGE("failed to reinstantiate video decoder after surface change."); 1344 return err; 1345 } 1346 1347 if (mLastVideoTimeUs >= 0) { 1348 mSeeking = SEEK; 1349 mSeekTimeUs = mLastVideoTimeUs; 1350 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1351 } 1352 1353 if (wasPlaying) { 1354 play_l(); 1355 } 1356 1357 return OK; 1358} 1359 1360void AwesomePlayer::setAudioSink( 1361 const sp<MediaPlayerBase::AudioSink> &audioSink) { 1362 Mutex::Autolock autoLock(mLock); 1363 1364 mAudioSink = audioSink; 1365} 1366 1367status_t AwesomePlayer::setLooping(bool shouldLoop) { 1368 Mutex::Autolock autoLock(mLock); 1369 1370 modifyFlags(LOOPING, CLEAR); 1371 1372 if (shouldLoop) { 1373 modifyFlags(LOOPING, SET); 1374 } 1375 1376 return OK; 1377} 1378 1379status_t AwesomePlayer::getDuration(int64_t *durationUs) { 1380 Mutex::Autolock autoLock(mMiscStateLock); 1381 1382 if (mDurationUs < 0) { 1383 return UNKNOWN_ERROR; 1384 } 1385 1386 *durationUs = mDurationUs; 1387 1388 return OK; 1389} 1390 1391status_t AwesomePlayer::getPosition(int64_t *positionUs) { 1392 if (mSeeking != NO_SEEK) { 1393 *positionUs = mSeekTimeUs; 1394 } else if (mVideoSource != NULL 1395 && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) { 1396 Mutex::Autolock autoLock(mMiscStateLock); 1397 *positionUs = mVideoTimeUs; 1398 } else if (mAudioPlayer != NULL) { 1399 *positionUs = mAudioPlayer->getMediaTimeUs(); 1400 } else { 1401 *positionUs = 0; 1402 } 1403 return OK; 1404} 1405 1406status_t AwesomePlayer::seekTo(int64_t timeUs) { 1407 ATRACE_CALL(); 1408 1409 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 1410 Mutex::Autolock autoLock(mLock); 1411 return seekTo_l(timeUs); 1412 } 1413 1414 return OK; 1415} 1416 1417status_t AwesomePlayer::seekTo_l(int64_t timeUs) { 1418 if (mFlags & CACHE_UNDERRUN) { 1419 modifyFlags(CACHE_UNDERRUN, CLEAR); 1420 play_l(); 1421 } 1422 1423 if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) { 1424 // Video playback completed before, there's no pending 1425 // video event right now. In order for this new seek 1426 // to be honored, we need to post one. 1427 1428 postVideoEvent_l(); 1429 } 1430 1431 mSeeking = SEEK; 1432 mSeekNotificationSent = false; 1433 mSeekTimeUs = timeUs; 1434 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1435 1436 if (mFlags & PLAYING) { 1437 notifyListener_l(MEDIA_PAUSED); 1438 mMediaRenderingStartGeneration = ++mStartGeneration; 1439 } 1440 1441 seekAudioIfNecessary_l(); 1442 1443 if (mFlags & TEXTPLAYER_INITIALIZED) { 1444 mTextDriver->seekToAsync(mSeekTimeUs); 1445 } 1446 1447 if (!(mFlags & PLAYING)) { 1448 ALOGV("seeking while paused, sending SEEK_COMPLETE notification" 1449 " immediately."); 1450 1451 notifyListener_l(MEDIA_SEEK_COMPLETE); 1452 mSeekNotificationSent = true; 1453 1454 if ((mFlags & PREPARED) && mVideoSource != NULL) { 1455 modifyFlags(SEEK_PREVIEW, SET); 1456 postVideoEvent_l(); 1457 } 1458 } 1459 1460 return OK; 1461} 1462 1463void AwesomePlayer::seekAudioIfNecessary_l() { 1464 if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) { 1465 mAudioPlayer->seekTo(mSeekTimeUs); 1466 1467 mWatchForAudioSeekComplete = true; 1468 mWatchForAudioEOS = true; 1469 1470 if (mDecryptHandle != NULL) { 1471 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1472 Playback::PAUSE, 0); 1473 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1474 Playback::START, mSeekTimeUs / 1000); 1475 } 1476 } 1477} 1478 1479void AwesomePlayer::setAudioSource(sp<MediaSource> source) { 1480 CHECK(source != NULL); 1481 1482 mAudioTrack = source; 1483} 1484 1485void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& source) { 1486 CHECK(source != NULL); 1487 1488 if (mTextDriver == NULL) { 1489 mTextDriver = new TimedTextDriver(mListener); 1490 } 1491 1492 mTextDriver->addInBandTextSource(trackIndex, source); 1493} 1494 1495status_t AwesomePlayer::initAudioDecoder() { 1496 ATRACE_CALL(); 1497 1498 sp<MetaData> meta = mAudioTrack->getFormat(); 1499 1500 const char *mime; 1501 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1502 // Check whether there is a hardware codec for this stream 1503 // This doesn't guarantee that the hardware has a free stream 1504 // but it avoids us attempting to open (and re-open) an offload 1505 // stream to hardware that doesn't have the necessary codec 1506 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC; 1507 if (mAudioSink != NULL) { 1508 streamType = mAudioSink->getAudioStreamType(); 1509 } 1510 1511 mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), 1512 isStreamingHTTP(), streamType); 1513 1514 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { 1515 ALOGV("createAudioPlayer: bypass OMX (raw)"); 1516 mAudioSource = mAudioTrack; 1517 } else { 1518 // If offloading we still create a OMX decoder as a fall-back 1519 // but we don't start it 1520 mOmxSource = OMXCodec::Create( 1521 mClient.interface(), mAudioTrack->getFormat(), 1522 false, // createEncoder 1523 mAudioTrack); 1524 1525 if (mOffloadAudio) { 1526 ALOGV("createAudioPlayer: bypass OMX (offload)"); 1527 mAudioSource = mAudioTrack; 1528 } else { 1529 mAudioSource = mOmxSource; 1530 } 1531 } 1532 1533 if (mAudioSource != NULL) { 1534 int64_t durationUs; 1535 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1536 Mutex::Autolock autoLock(mMiscStateLock); 1537 if (mDurationUs < 0 || durationUs > mDurationUs) { 1538 mDurationUs = durationUs; 1539 } 1540 } 1541 1542 status_t err = mAudioSource->start(); 1543 1544 if (err != OK) { 1545 mAudioSource.clear(); 1546 mOmxSource.clear(); 1547 return err; 1548 } 1549 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) { 1550 // For legacy reasons we're simply going to ignore the absence 1551 // of an audio decoder for QCELP instead of aborting playback 1552 // altogether. 1553 return OK; 1554 } 1555 1556 if (mAudioSource != NULL) { 1557 Mutex::Autolock autoLock(mStatsLock); 1558 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 1559 const char *component; 1560 if (!mAudioSource->getFormat() 1561 ->findCString(kKeyDecoderComponent, &component)) { 1562 component = "none"; 1563 } 1564 1565 stat->mDecoderName = component; 1566 } 1567 1568 return mAudioSource != NULL ? OK : UNKNOWN_ERROR; 1569} 1570 1571void AwesomePlayer::setVideoSource(sp<MediaSource> source) { 1572 CHECK(source != NULL); 1573 1574 mVideoTrack = source; 1575} 1576 1577status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { 1578 ATRACE_CALL(); 1579 1580 // Either the application or the DRM system can independently say 1581 // that there must be a hardware-protected path to an external video sink. 1582 // For now we always require a hardware-protected path to external video sink 1583 // if content is DRMed, but eventually this could be optional per DRM agent. 1584 // When the application wants protection, then 1585 // (USE_SURFACE_ALLOC && (mSurface != 0) && 1586 // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp)) 1587 // will be true, but that part is already handled by SurfaceFlinger. 1588 1589#ifdef DEBUG_HDCP 1590 // For debugging, we allow a system property to control the protected usage. 1591 // In case of uninitialized or unexpected property, we default to "DRM only". 1592 bool setProtectionBit = false; 1593 char value[PROPERTY_VALUE_MAX]; 1594 if (property_get("persist.sys.hdcp_checking", value, NULL)) { 1595 if (!strcmp(value, "never")) { 1596 // nop 1597 } else if (!strcmp(value, "always")) { 1598 setProtectionBit = true; 1599 } else if (!strcmp(value, "drm-only")) { 1600 if (mDecryptHandle != NULL) { 1601 setProtectionBit = true; 1602 } 1603 // property value is empty, or unexpected value 1604 } else { 1605 if (mDecryptHandle != NULL) { 1606 setProtectionBit = true; 1607 } 1608 } 1609 // can' read property value 1610 } else { 1611 if (mDecryptHandle != NULL) { 1612 setProtectionBit = true; 1613 } 1614 } 1615 // note that usage bit is already cleared, so no need to clear it in the "else" case 1616 if (setProtectionBit) { 1617 flags |= OMXCodec::kEnableGrallocUsageProtected; 1618 } 1619#else 1620 if (mDecryptHandle != NULL) { 1621 flags |= OMXCodec::kEnableGrallocUsageProtected; 1622 } 1623#endif 1624 ALOGV("initVideoDecoder flags=0x%x", flags); 1625 mVideoSource = OMXCodec::Create( 1626 mClient.interface(), mVideoTrack->getFormat(), 1627 false, // createEncoder 1628 mVideoTrack, 1629 NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL); 1630 1631 if (mVideoSource != NULL) { 1632 int64_t durationUs; 1633 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1634 Mutex::Autolock autoLock(mMiscStateLock); 1635 if (mDurationUs < 0 || durationUs > mDurationUs) { 1636 mDurationUs = durationUs; 1637 } 1638 } 1639 1640 status_t err = mVideoSource->start(); 1641 1642 if (err != OK) { 1643 ALOGE("failed to start video source"); 1644 mVideoSource.clear(); 1645 return err; 1646 } 1647 } 1648 1649 if (mVideoSource != NULL) { 1650 const char *componentName; 1651 CHECK(mVideoSource->getFormat() 1652 ->findCString(kKeyDecoderComponent, &componentName)); 1653 1654 { 1655 Mutex::Autolock autoLock(mStatsLock); 1656 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 1657 1658 stat->mDecoderName = componentName; 1659 } 1660 1661 static const char *kPrefix = "OMX.Nvidia."; 1662 static const char *kSuffix = ".decode"; 1663 static const size_t kSuffixLength = strlen(kSuffix); 1664 1665 size_t componentNameLength = strlen(componentName); 1666 1667 if (!strncmp(componentName, kPrefix, strlen(kPrefix)) 1668 && componentNameLength >= kSuffixLength 1669 && !strcmp(&componentName[ 1670 componentNameLength - kSuffixLength], kSuffix)) { 1671 modifyFlags(SLOW_DECODER_HACK, SET); 1672 } 1673 } 1674 1675 return mVideoSource != NULL ? OK : UNKNOWN_ERROR; 1676} 1677 1678void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { 1679 ATRACE_CALL(); 1680 1681 if (mSeeking == SEEK_VIDEO_ONLY) { 1682 mSeeking = NO_SEEK; 1683 return; 1684 } 1685 1686 if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) { 1687 return; 1688 } 1689 1690 // If we paused, then seeked, then resumed, it is possible that we have 1691 // signaled SEEK_COMPLETE at a copmletely different media time than where 1692 // we are now resuming. Signal new position to media time provider. 1693 // Cannot signal another SEEK_COMPLETE, as existing clients may not expect 1694 // multiple SEEK_COMPLETE responses to a single seek() request. 1695 if (mSeekNotificationSent && abs(mSeekTimeUs - videoTimeUs) > 10000) { 1696 // notify if we are resuming more than 10ms away from desired seek time 1697 notifyListener_l(MEDIA_SKIPPED); 1698 } 1699 1700 if (mAudioPlayer != NULL) { 1701 ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6); 1702 1703 // If we don't have a video time, seek audio to the originally 1704 // requested seek time instead. 1705 1706 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs); 1707 mWatchForAudioSeekComplete = true; 1708 mWatchForAudioEOS = true; 1709 } else if (!mSeekNotificationSent) { 1710 // If we're playing video only, report seek complete now, 1711 // otherwise audio player will notify us later. 1712 notifyListener_l(MEDIA_SEEK_COMPLETE); 1713 mSeekNotificationSent = true; 1714 } 1715 1716 modifyFlags(FIRST_FRAME, SET); 1717 mSeeking = NO_SEEK; 1718 1719 if (mDecryptHandle != NULL) { 1720 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1721 Playback::PAUSE, 0); 1722 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1723 Playback::START, videoTimeUs / 1000); 1724 } 1725} 1726 1727void AwesomePlayer::onVideoEvent() { 1728 ATRACE_CALL(); 1729 Mutex::Autolock autoLock(mLock); 1730 if (!mVideoEventPending) { 1731 // The event has been cancelled in reset_l() but had already 1732 // been scheduled for execution at that time. 1733 return; 1734 } 1735 mVideoEventPending = false; 1736 1737 if (mSeeking != NO_SEEK) { 1738 if (mVideoBuffer) { 1739 mVideoBuffer->release(); 1740 mVideoBuffer = NULL; 1741 } 1742 1743 if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL 1744 && !(mFlags & SEEK_PREVIEW)) { 1745 // We're going to seek the video source first, followed by 1746 // the audio source. 1747 // In order to avoid jumps in the DataSource offset caused by 1748 // the audio codec prefetching data from the old locations 1749 // while the video codec is already reading data from the new 1750 // locations, we'll "pause" the audio source, causing it to 1751 // stop reading input data until a subsequent seek. 1752 1753 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1754 mAudioPlayer->pause(); 1755 1756 modifyFlags(AUDIO_RUNNING, CLEAR); 1757 } 1758 mAudioSource->pause(); 1759 } 1760 } 1761 1762 if (!mVideoBuffer) { 1763 MediaSource::ReadOptions options; 1764 if (mSeeking != NO_SEEK) { 1765 ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); 1766 1767 options.setSeekTo( 1768 mSeekTimeUs, 1769 mSeeking == SEEK_VIDEO_ONLY 1770 ? MediaSource::ReadOptions::SEEK_NEXT_SYNC 1771 : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); 1772 } 1773 for (;;) { 1774 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1775 options.clearSeekTo(); 1776 1777 if (err != OK) { 1778 CHECK(mVideoBuffer == NULL); 1779 1780 if (err == INFO_FORMAT_CHANGED) { 1781 ALOGV("VideoSource signalled format change."); 1782 1783 notifyVideoSize_l(); 1784 1785 if (mVideoRenderer != NULL) { 1786 mVideoRendererIsPreview = false; 1787 initRenderer_l(); 1788 } 1789 continue; 1790 } 1791 1792 // So video playback is complete, but we may still have 1793 // a seek request pending that needs to be applied 1794 // to the audio track. 1795 if (mSeeking != NO_SEEK) { 1796 ALOGV("video stream ended while seeking!"); 1797 } 1798 finishSeekIfNecessary(-1); 1799 1800 if (mAudioPlayer != NULL 1801 && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1802 startAudioPlayer_l(); 1803 } 1804 1805 modifyFlags(VIDEO_AT_EOS, SET); 1806 postStreamDoneEvent_l(err); 1807 return; 1808 } 1809 1810 if (mVideoBuffer->range_length() == 0) { 1811 // Some decoders, notably the PV AVC software decoder 1812 // return spurious empty buffers that we just want to ignore. 1813 1814 mVideoBuffer->release(); 1815 mVideoBuffer = NULL; 1816 continue; 1817 } 1818 1819 break; 1820 } 1821 1822 { 1823 Mutex::Autolock autoLock(mStatsLock); 1824 ++mStats.mNumVideoFramesDecoded; 1825 } 1826 } 1827 1828 int64_t timeUs; 1829 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 1830 1831 mLastVideoTimeUs = timeUs; 1832 1833 if (mSeeking == SEEK_VIDEO_ONLY) { 1834 if (mSeekTimeUs > timeUs) { 1835 ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us", 1836 mSeekTimeUs, timeUs); 1837 } 1838 } 1839 1840 { 1841 Mutex::Autolock autoLock(mMiscStateLock); 1842 mVideoTimeUs = timeUs; 1843 } 1844 1845 SeekType wasSeeking = mSeeking; 1846 finishSeekIfNecessary(timeUs); 1847 1848 if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1849 status_t err = startAudioPlayer_l(); 1850 if (err != OK) { 1851 ALOGE("Starting the audio player failed w/ err %d", err); 1852 return; 1853 } 1854 } 1855 1856 if ((mFlags & TEXTPLAYER_INITIALIZED) 1857 && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) { 1858 mTextDriver->start(); 1859 modifyFlags(TEXT_RUNNING, SET); 1860 } 1861 1862 TimeSource *ts = 1863 ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED)) 1864 ? &mSystemTimeSource : mTimeSource; 1865 int64_t systemTimeUs = mSystemTimeSource.getRealTimeUs(); 1866 int64_t looperTimeUs = ALooper::GetNowUs(); 1867 1868 if (mFlags & FIRST_FRAME) { 1869 modifyFlags(FIRST_FRAME, CLEAR); 1870 mSinceLastDropped = 0; 1871 mClockEstimator->reset(); 1872 mTimeSourceDeltaUs = estimateRealTimeUs(ts, systemTimeUs) - timeUs; 1873 } 1874 1875 int64_t realTimeUs, mediaTimeUs; 1876 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL 1877 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 1878 ALOGV("updating TSdelta (%" PRId64 " => %" PRId64 " change %" PRId64 ")", 1879 mTimeSourceDeltaUs, realTimeUs - mediaTimeUs, 1880 mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)); 1881 ATRACE_INT("TS delta change (ms)", (mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)) / 1E3); 1882 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 1883 } 1884 1885 if (wasSeeking == SEEK_VIDEO_ONLY) { 1886 int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs; 1887 1888 int64_t latenessUs = nowUs - timeUs; 1889 1890 ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); 1891 1892 if (latenessUs > 0) { 1893 ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6); 1894 } 1895 } 1896 1897 int64_t latenessUs = 0; 1898 if (wasSeeking == NO_SEEK) { 1899 // Let's display the first frame after seeking right away. 1900 1901 int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs; 1902 1903 latenessUs = nowUs - timeUs; 1904 1905 ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); 1906 1907 if (latenessUs > 500000ll 1908 && mAudioPlayer != NULL 1909 && mAudioPlayer->getMediaTimeMapping( 1910 &realTimeUs, &mediaTimeUs)) { 1911 if (mWVMExtractor == NULL) { 1912 ALOGI("we're much too late (%.2f secs), video skipping ahead", 1913 latenessUs / 1E6); 1914 1915 mVideoBuffer->release(); 1916 mVideoBuffer = NULL; 1917 1918 mSeeking = SEEK_VIDEO_ONLY; 1919 mSeekTimeUs = mediaTimeUs; 1920 1921 postVideoEvent_l(); 1922 return; 1923 } else { 1924 // The widevine extractor doesn't deal well with seeking 1925 // audio and video independently. We'll just have to wait 1926 // until the decoder catches up, which won't be long at all. 1927 ALOGI("we're very late (%.2f secs)", latenessUs / 1E6); 1928 } 1929 } 1930 1931 if (latenessUs > 40000) { 1932 // We're more than 40ms late. 1933 ALOGV("we're late by %lld us (%.2f secs)", 1934 latenessUs, latenessUs / 1E6); 1935 1936 if (!(mFlags & SLOW_DECODER_HACK) 1937 || mSinceLastDropped > FRAME_DROP_FREQ) 1938 { 1939 ALOGV("we're late by %lld us (%.2f secs) dropping " 1940 "one after %d frames", 1941 latenessUs, latenessUs / 1E6, mSinceLastDropped); 1942 1943 mSinceLastDropped = 0; 1944 mVideoBuffer->release(); 1945 mVideoBuffer = NULL; 1946 1947 { 1948 Mutex::Autolock autoLock(mStatsLock); 1949 ++mStats.mNumVideoFramesDropped; 1950 } 1951 1952 postVideoEvent_l(0); 1953 return; 1954 } 1955 } 1956 1957 if (latenessUs < -30000) { 1958 // We're more than 30ms early, schedule at most 20 ms before time due 1959 postVideoEvent_l(latenessUs < -60000 ? 30000 : -latenessUs - 20000); 1960 return; 1961 } 1962 } 1963 1964 if ((mNativeWindow != NULL) 1965 && (mVideoRendererIsPreview || mVideoRenderer == NULL)) { 1966 mVideoRendererIsPreview = false; 1967 1968 initRenderer_l(); 1969 } 1970 1971 if (mVideoRenderer != NULL) { 1972 mSinceLastDropped++; 1973 mVideoBuffer->meta_data()->setInt64(kKeyTime, looperTimeUs - latenessUs); 1974 1975 mVideoRenderer->render(mVideoBuffer); 1976 if (!mVideoRenderingStarted) { 1977 mVideoRenderingStarted = true; 1978 notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START); 1979 } 1980 1981 if (mFlags & PLAYING) { 1982 notifyIfMediaStarted_l(); 1983 } 1984 } 1985 1986 mVideoBuffer->release(); 1987 mVideoBuffer = NULL; 1988 1989 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) { 1990 modifyFlags(SEEK_PREVIEW, CLEAR); 1991 return; 1992 } 1993 1994 /* get next frame time */ 1995 if (wasSeeking == NO_SEEK) { 1996 MediaSource::ReadOptions options; 1997 for (;;) { 1998 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1999 if (err != OK) { 2000 // deal with any errors next time 2001 CHECK(mVideoBuffer == NULL); 2002 postVideoEvent_l(0); 2003 return; 2004 } 2005 2006 if (mVideoBuffer->range_length() != 0) { 2007 break; 2008 } 2009 2010 // Some decoders, notably the PV AVC software decoder 2011 // return spurious empty buffers that we just want to ignore. 2012 2013 mVideoBuffer->release(); 2014 mVideoBuffer = NULL; 2015 } 2016 2017 { 2018 Mutex::Autolock autoLock(mStatsLock); 2019 ++mStats.mNumVideoFramesDecoded; 2020 } 2021 2022 int64_t nextTimeUs; 2023 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &nextTimeUs)); 2024 systemTimeUs = mSystemTimeSource.getRealTimeUs(); 2025 int64_t delayUs = nextTimeUs - estimateRealTimeUs(ts, systemTimeUs) + mTimeSourceDeltaUs; 2026 ATRACE_INT("Frame delta (ms)", (nextTimeUs - timeUs) / 1E3); 2027 ALOGV("next frame in %" PRId64, delayUs); 2028 // try to schedule 30ms before time due 2029 postVideoEvent_l(delayUs > 60000 ? 30000 : (delayUs < 30000 ? 0 : delayUs - 30000)); 2030 return; 2031 } 2032 2033 postVideoEvent_l(); 2034} 2035 2036int64_t AwesomePlayer::estimateRealTimeUs(TimeSource *ts, int64_t systemTimeUs) { 2037 if (ts == &mSystemTimeSource) { 2038 return systemTimeUs; 2039 } else { 2040 return (int64_t)mClockEstimator->estimate(systemTimeUs, ts->getRealTimeUs()); 2041 } 2042} 2043 2044void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 2045 ATRACE_CALL(); 2046 2047 if (mVideoEventPending) { 2048 return; 2049 } 2050 2051 mVideoEventPending = true; 2052 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 2053} 2054 2055void AwesomePlayer::postStreamDoneEvent_l(status_t status) { 2056 if (mStreamDoneEventPending) { 2057 return; 2058 } 2059 mStreamDoneEventPending = true; 2060 2061 mStreamDoneStatus = status; 2062 mQueue.postEvent(mStreamDoneEvent); 2063} 2064 2065void AwesomePlayer::postBufferingEvent_l() { 2066 if (mBufferingEventPending) { 2067 return; 2068 } 2069 mBufferingEventPending = true; 2070 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); 2071} 2072 2073void AwesomePlayer::postVideoLagEvent_l() { 2074 if (mVideoLagEventPending) { 2075 return; 2076 } 2077 mVideoLagEventPending = true; 2078 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); 2079} 2080 2081void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) { 2082 Mutex::Autolock autoLock(mAudioLock); 2083 if (mAudioStatusEventPending) { 2084 return; 2085 } 2086 mAudioStatusEventPending = true; 2087 // Do not honor delay when looping in order to limit audio gap 2088 if (mFlags & (LOOPING | AUTO_LOOPING)) { 2089 delayUs = 0; 2090 } 2091 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs); 2092} 2093 2094void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) { 2095 Mutex::Autolock autoLock(mAudioLock); 2096 if (mAudioTearDownEventPending) { 2097 return; 2098 } 2099 mAudioTearDownEventPending = true; 2100 mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs); 2101} 2102 2103void AwesomePlayer::onCheckAudioStatus() { 2104 { 2105 Mutex::Autolock autoLock(mAudioLock); 2106 if (!mAudioStatusEventPending) { 2107 // Event was dispatched and while we were blocking on the mutex, 2108 // has already been cancelled. 2109 return; 2110 } 2111 2112 mAudioStatusEventPending = false; 2113 } 2114 2115 Mutex::Autolock autoLock(mLock); 2116 2117 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { 2118 mWatchForAudioSeekComplete = false; 2119 2120 if (!mSeekNotificationSent) { 2121 notifyListener_l(MEDIA_SEEK_COMPLETE); 2122 mSeekNotificationSent = true; 2123 } 2124 2125 if (mVideoSource == NULL) { 2126 // For video the mSeeking flag is always reset in finishSeekIfNecessary 2127 mSeeking = NO_SEEK; 2128 } 2129 2130 notifyIfMediaStarted_l(); 2131 } 2132 2133 status_t finalStatus; 2134 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) { 2135 mWatchForAudioEOS = false; 2136 modifyFlags(AUDIO_AT_EOS, SET); 2137 modifyFlags(FIRST_FRAME, SET); 2138 postStreamDoneEvent_l(finalStatus); 2139 } 2140} 2141 2142status_t AwesomePlayer::prepare() { 2143 ATRACE_CALL(); 2144 Mutex::Autolock autoLock(mLock); 2145 return prepare_l(); 2146} 2147 2148status_t AwesomePlayer::prepare_l() { 2149 if (mFlags & PREPARED) { 2150 return OK; 2151 } 2152 2153 if (mFlags & PREPARING) { 2154 return UNKNOWN_ERROR; 2155 } 2156 2157 mIsAsyncPrepare = false; 2158 status_t err = prepareAsync_l(); 2159 2160 if (err != OK) { 2161 return err; 2162 } 2163 2164 while (mFlags & PREPARING) { 2165 mPreparedCondition.wait(mLock); 2166 } 2167 2168 return mPrepareResult; 2169} 2170 2171status_t AwesomePlayer::prepareAsync() { 2172 ATRACE_CALL(); 2173 Mutex::Autolock autoLock(mLock); 2174 2175 if (mFlags & PREPARING) { 2176 return UNKNOWN_ERROR; // async prepare already pending 2177 } 2178 2179 mIsAsyncPrepare = true; 2180 return prepareAsync_l(); 2181} 2182 2183status_t AwesomePlayer::prepareAsync_l() { 2184 if (mFlags & PREPARING) { 2185 return UNKNOWN_ERROR; // async prepare already pending 2186 } 2187 2188 if (!mQueueStarted) { 2189 mQueue.start(); 2190 mQueueStarted = true; 2191 } 2192 2193 modifyFlags(PREPARING, SET); 2194 mAsyncPrepareEvent = new AwesomeEvent( 2195 this, &AwesomePlayer::onPrepareAsyncEvent); 2196 2197 mQueue.postEvent(mAsyncPrepareEvent); 2198 2199 return OK; 2200} 2201 2202status_t AwesomePlayer::finishSetDataSource_l() { 2203 ATRACE_CALL(); 2204 sp<DataSource> dataSource; 2205 2206 bool isWidevineStreaming = false; 2207 if (!strncasecmp("widevine://", mUri.string(), 11)) { 2208 isWidevineStreaming = true; 2209 2210 String8 newURI = String8("http://"); 2211 newURI.append(mUri.string() + 11); 2212 2213 mUri = newURI; 2214 } 2215 2216 AString sniffedMIME; 2217 2218 if (!strncasecmp("http://", mUri.string(), 7) 2219 || !strncasecmp("https://", mUri.string(), 8) 2220 || isWidevineStreaming) { 2221 mConnectingDataSource = HTTPBase::Create( 2222 (mFlags & INCOGNITO) 2223 ? HTTPBase::kFlagIncognito 2224 : 0); 2225 2226 if (mUIDValid) { 2227 mConnectingDataSource->setUID(mUID); 2228 } 2229 2230 String8 cacheConfig; 2231 bool disconnectAtHighwatermark; 2232 NuCachedSource2::RemoveCacheSpecificHeaders( 2233 &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark); 2234 2235 mLock.unlock(); 2236 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); 2237 mLock.lock(); 2238 2239 if (err != OK) { 2240 mConnectingDataSource.clear(); 2241 2242 ALOGI("mConnectingDataSource->connect() returned %d", err); 2243 return err; 2244 } 2245 2246 if (!isWidevineStreaming) { 2247 // The widevine extractor does its own caching. 2248 2249#if 0 2250 mCachedSource = new NuCachedSource2( 2251 new ThrottledSource( 2252 mConnectingDataSource, 50 * 1024 /* bytes/sec */)); 2253#else 2254 mCachedSource = new NuCachedSource2( 2255 mConnectingDataSource, 2256 cacheConfig.isEmpty() ? NULL : cacheConfig.string(), 2257 disconnectAtHighwatermark); 2258#endif 2259 2260 dataSource = mCachedSource; 2261 } else { 2262 dataSource = mConnectingDataSource; 2263 } 2264 2265 mConnectingDataSource.clear(); 2266 2267 String8 contentType = dataSource->getMIMEType(); 2268 2269 if (strncasecmp(contentType.string(), "audio/", 6)) { 2270 // We're not doing this for streams that appear to be audio-only 2271 // streams to ensure that even low bandwidth streams start 2272 // playing back fairly instantly. 2273 2274 // We're going to prefill the cache before trying to instantiate 2275 // the extractor below, as the latter is an operation that otherwise 2276 // could block on the datasource for a significant amount of time. 2277 // During that time we'd be unable to abort the preparation phase 2278 // without this prefill. 2279 if (mCachedSource != NULL) { 2280 // We're going to prefill the cache before trying to instantiate 2281 // the extractor below, as the latter is an operation that otherwise 2282 // could block on the datasource for a significant amount of time. 2283 // During that time we'd be unable to abort the preparation phase 2284 // without this prefill. 2285 2286 mLock.unlock(); 2287 2288 // Initially make sure we have at least 192 KB for the sniff 2289 // to complete without blocking. 2290 static const size_t kMinBytesForSniffing = 192 * 1024; 2291 2292 off64_t metaDataSize = -1ll; 2293 for (;;) { 2294 status_t finalStatus; 2295 size_t cachedDataRemaining = 2296 mCachedSource->approxDataRemaining(&finalStatus); 2297 2298 if (finalStatus != OK 2299 || (metaDataSize >= 0 2300 && cachedDataRemaining >= metaDataSize) 2301 || (mFlags & PREPARE_CANCELLED)) { 2302 break; 2303 } 2304 2305 ALOGV("now cached %d bytes of data", cachedDataRemaining); 2306 2307 if (metaDataSize < 0 2308 && cachedDataRemaining >= kMinBytesForSniffing) { 2309 String8 tmp; 2310 float confidence; 2311 sp<AMessage> meta; 2312 if (!dataSource->sniff(&tmp, &confidence, &meta)) { 2313 mLock.lock(); 2314 return UNKNOWN_ERROR; 2315 } 2316 2317 // We successfully identified the file's extractor to 2318 // be, remember this mime type so we don't have to 2319 // sniff it again when we call MediaExtractor::Create() 2320 // below. 2321 sniffedMIME = tmp.string(); 2322 2323 if (meta == NULL 2324 || !meta->findInt64("meta-data-size", 2325 reinterpret_cast<int64_t*>(&metaDataSize))) { 2326 metaDataSize = kHighWaterMarkBytes; 2327 } 2328 2329 CHECK_GE(metaDataSize, 0ll); 2330 ALOGV("metaDataSize = %lld bytes", metaDataSize); 2331 } 2332 2333 usleep(200000); 2334 } 2335 2336 mLock.lock(); 2337 } 2338 2339 if (mFlags & PREPARE_CANCELLED) { 2340 ALOGI("Prepare cancelled while waiting for initial cache fill."); 2341 return UNKNOWN_ERROR; 2342 } 2343 } 2344 } else { 2345 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); 2346 } 2347 2348 if (dataSource == NULL) { 2349 return UNKNOWN_ERROR; 2350 } 2351 2352 sp<MediaExtractor> extractor; 2353 2354 if (isWidevineStreaming) { 2355 String8 mimeType; 2356 float confidence; 2357 sp<AMessage> dummy; 2358 bool success; 2359 2360 // SniffWVM is potentially blocking since it may require network access. 2361 // Do not call it with mLock held. 2362 mLock.unlock(); 2363 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 2364 mLock.lock(); 2365 2366 if (!success 2367 || strcasecmp( 2368 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 2369 return ERROR_UNSUPPORTED; 2370 } 2371 2372 mWVMExtractor = new WVMExtractor(dataSource); 2373 mWVMExtractor->setAdaptiveStreamingMode(true); 2374 if (mUIDValid) 2375 mWVMExtractor->setUID(mUID); 2376 extractor = mWVMExtractor; 2377 } else { 2378 extractor = MediaExtractor::Create( 2379 dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); 2380 2381 if (extractor == NULL) { 2382 return UNKNOWN_ERROR; 2383 } 2384 } 2385 2386 if (extractor->getDrmFlag()) { 2387 checkDrmStatus(dataSource); 2388 } 2389 2390 status_t err = setDataSource_l(extractor); 2391 2392 if (err != OK) { 2393 mWVMExtractor.clear(); 2394 2395 return err; 2396 } 2397 2398 return OK; 2399} 2400 2401void AwesomePlayer::abortPrepare(status_t err) { 2402 CHECK(err != OK); 2403 2404 if (mIsAsyncPrepare) { 2405 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 2406 } 2407 2408 mPrepareResult = err; 2409 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2410 mAsyncPrepareEvent = NULL; 2411 mPreparedCondition.broadcast(); 2412 mAudioTearDown = false; 2413} 2414 2415// static 2416bool AwesomePlayer::ContinuePreparation(void *cookie) { 2417 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie); 2418 2419 return (me->mFlags & PREPARE_CANCELLED) == 0; 2420} 2421 2422void AwesomePlayer::onPrepareAsyncEvent() { 2423 Mutex::Autolock autoLock(mLock); 2424 beginPrepareAsync_l(); 2425} 2426 2427void AwesomePlayer::beginPrepareAsync_l() { 2428 if (mFlags & PREPARE_CANCELLED) { 2429 ALOGI("prepare was cancelled before doing anything"); 2430 abortPrepare(UNKNOWN_ERROR); 2431 return; 2432 } 2433 2434 if (mUri.size() > 0) { 2435 status_t err = finishSetDataSource_l(); 2436 2437 if (err != OK) { 2438 abortPrepare(err); 2439 return; 2440 } 2441 } 2442 2443 if (mVideoTrack != NULL && mVideoSource == NULL) { 2444 status_t err = initVideoDecoder(); 2445 2446 if (err != OK) { 2447 abortPrepare(err); 2448 return; 2449 } 2450 } 2451 2452 if (mAudioTrack != NULL && mAudioSource == NULL) { 2453 status_t err = initAudioDecoder(); 2454 2455 if (err != OK) { 2456 abortPrepare(err); 2457 return; 2458 } 2459 } 2460 2461 modifyFlags(PREPARING_CONNECTED, SET); 2462 2463 if (isStreamingHTTP()) { 2464 postBufferingEvent_l(); 2465 } else { 2466 finishAsyncPrepare_l(); 2467 } 2468} 2469 2470void AwesomePlayer::finishAsyncPrepare_l() { 2471 if (mIsAsyncPrepare) { 2472 if (mVideoSource == NULL) { 2473 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); 2474 } else { 2475 notifyVideoSize_l(); 2476 } 2477 2478 notifyListener_l(MEDIA_PREPARED); 2479 } 2480 2481 mPrepareResult = OK; 2482 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2483 modifyFlags(PREPARED, SET); 2484 mAsyncPrepareEvent = NULL; 2485 mPreparedCondition.broadcast(); 2486 2487 if (mAudioTearDown) { 2488 if (mPrepareResult == OK) { 2489 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 2490 seekTo_l(mAudioTearDownPosition); 2491 } 2492 2493 if (mAudioTearDownWasPlaying) { 2494 modifyFlags(CACHE_UNDERRUN, CLEAR); 2495 play_l(); 2496 } 2497 } 2498 mAudioTearDown = false; 2499 } 2500} 2501 2502uint32_t AwesomePlayer::flags() const { 2503 return mExtractorFlags; 2504} 2505 2506void AwesomePlayer::postAudioEOS(int64_t delayUs) { 2507 postCheckAudioStatusEvent(delayUs); 2508} 2509 2510void AwesomePlayer::postAudioSeekComplete() { 2511 postCheckAudioStatusEvent(0); 2512} 2513 2514void AwesomePlayer::postAudioTearDown() { 2515 postAudioTearDownEvent(0); 2516} 2517 2518status_t AwesomePlayer::setParameter(int key, const Parcel &request) { 2519 switch (key) { 2520 case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS: 2521 { 2522 return setCacheStatCollectFreq(request); 2523 } 2524 case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE: 2525 { 2526 if (mAudioPlayer != NULL) { 2527 return mAudioPlayer->setPlaybackRatePermille(request.readInt32()); 2528 } else { 2529 return NO_INIT; 2530 } 2531 } 2532 default: 2533 { 2534 return ERROR_UNSUPPORTED; 2535 } 2536 } 2537} 2538 2539status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) { 2540 if (mCachedSource != NULL) { 2541 int32_t freqMs = request.readInt32(); 2542 ALOGD("Request to keep cache stats in the past %d ms", 2543 freqMs); 2544 return mCachedSource->setCacheStatCollectFreq(freqMs); 2545 } 2546 return ERROR_UNSUPPORTED; 2547} 2548 2549status_t AwesomePlayer::getParameter(int key, Parcel *reply) { 2550 switch (key) { 2551 case KEY_PARAMETER_AUDIO_CHANNEL_COUNT: 2552 { 2553 int32_t channelCount; 2554 if (mAudioTrack == 0 || 2555 !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) { 2556 channelCount = 0; 2557 } 2558 reply->writeInt32(channelCount); 2559 } 2560 return OK; 2561 default: 2562 { 2563 return ERROR_UNSUPPORTED; 2564 } 2565 } 2566} 2567 2568status_t AwesomePlayer::getTrackInfo(Parcel *reply) const { 2569 Mutex::Autolock autoLock(mLock); 2570 size_t trackCount = mExtractor->countTracks(); 2571 if (mTextDriver != NULL) { 2572 trackCount += mTextDriver->countExternalTracks(); 2573 } 2574 2575 reply->writeInt32(trackCount); 2576 for (size_t i = 0; i < mExtractor->countTracks(); ++i) { 2577 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 2578 2579 const char *_mime; 2580 CHECK(meta->findCString(kKeyMIMEType, &_mime)); 2581 2582 String8 mime = String8(_mime); 2583 2584 reply->writeInt32(2); // 2 fields 2585 2586 if (!strncasecmp(mime.string(), "video/", 6)) { 2587 reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO); 2588 } else if (!strncasecmp(mime.string(), "audio/", 6)) { 2589 reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO); 2590 } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { 2591 reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT); 2592 } else { 2593 reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN); 2594 } 2595 2596 const char *lang; 2597 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 2598 lang = "und"; 2599 } 2600 reply->writeString16(String16(lang)); 2601 } 2602 2603 if (mTextDriver != NULL) { 2604 mTextDriver->getExternalTrackInfo(reply); 2605 } 2606 return OK; 2607} 2608 2609status_t AwesomePlayer::selectAudioTrack_l( 2610 const sp<MediaSource>& source, size_t trackIndex) { 2611 2612 ALOGI("selectAudioTrack_l: trackIndex=%zu, mFlags=0x%x", trackIndex, mFlags); 2613 2614 { 2615 Mutex::Autolock autoLock(mStatsLock); 2616 if ((ssize_t)trackIndex == mActiveAudioTrackIndex) { 2617 ALOGI("Track %zu is active. Does nothing.", trackIndex); 2618 return OK; 2619 } 2620 //mStats.mFlags = mFlags; 2621 } 2622 2623 if (mSeeking != NO_SEEK) { 2624 ALOGE("Selecting a track while seeking is not supported"); 2625 return ERROR_UNSUPPORTED; 2626 } 2627 2628 if ((mFlags & PREPARED) == 0) { 2629 ALOGE("Data source has not finished preparation"); 2630 return ERROR_UNSUPPORTED; 2631 } 2632 2633 CHECK(source != NULL); 2634 bool wasPlaying = (mFlags & PLAYING) != 0; 2635 2636 pause_l(); 2637 2638 int64_t curTimeUs; 2639 CHECK_EQ(getPosition(&curTimeUs), (status_t)OK); 2640 2641 if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED)) 2642 && mAudioSource != NULL) { 2643 // If we had an audio player, it would have effectively 2644 // taken possession of the audio source and stopped it when 2645 // _it_ is stopped. Otherwise this is still our responsibility. 2646 mAudioSource->stop(); 2647 } 2648 mAudioSource.clear(); 2649 mOmxSource.clear(); 2650 2651 mTimeSource = NULL; 2652 2653 delete mAudioPlayer; 2654 mAudioPlayer = NULL; 2655 2656 modifyFlags(AUDIOPLAYER_STARTED, CLEAR); 2657 2658 setAudioSource(source); 2659 2660 modifyFlags(AUDIO_AT_EOS, CLEAR); 2661 modifyFlags(AT_EOS, CLEAR); 2662 2663 status_t err; 2664 if ((err = initAudioDecoder()) != OK) { 2665 ALOGE("Failed to init audio decoder: 0x%x", err); 2666 return err; 2667 } 2668 2669 mSeekNotificationSent = true; 2670 seekTo_l(curTimeUs); 2671 2672 if (wasPlaying) { 2673 play_l(); 2674 } 2675 2676 mActiveAudioTrackIndex = trackIndex; 2677 2678 return OK; 2679} 2680 2681status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) { 2682 ATRACE_CALL(); 2683 ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select); 2684 Mutex::Autolock autoLock(mLock); 2685 size_t trackCount = mExtractor->countTracks(); 2686 if (mTextDriver != NULL) { 2687 trackCount += mTextDriver->countExternalTracks(); 2688 } 2689 if (trackIndex >= trackCount) { 2690 ALOGE("Track index (%zu) is out of range [0, %zu)", trackIndex, trackCount); 2691 return ERROR_OUT_OF_RANGE; 2692 } 2693 2694 bool isAudioTrack = false; 2695 if (trackIndex < mExtractor->countTracks()) { 2696 sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex); 2697 const char *mime; 2698 CHECK(meta->findCString(kKeyMIMEType, &mime)); 2699 isAudioTrack = !strncasecmp(mime, "audio/", 6); 2700 2701 if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) { 2702 ALOGE("Track %zu is not either audio or timed text", trackIndex); 2703 return ERROR_UNSUPPORTED; 2704 } 2705 } 2706 2707 if (isAudioTrack) { 2708 if (!select) { 2709 ALOGE("Deselect an audio track (%zu) is not supported", trackIndex); 2710 return ERROR_UNSUPPORTED; 2711 } 2712 return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex); 2713 } 2714 2715 // Timed text track handling 2716 if (mTextDriver == NULL) { 2717 return INVALID_OPERATION; 2718 } 2719 2720 status_t err = OK; 2721 if (select) { 2722 err = mTextDriver->selectTrack(trackIndex); 2723 if (err == OK) { 2724 modifyFlags(TEXTPLAYER_INITIALIZED, SET); 2725 if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) { 2726 mTextDriver->start(); 2727 modifyFlags(TEXT_RUNNING, SET); 2728 } 2729 } 2730 } else { 2731 err = mTextDriver->unselectTrack(trackIndex); 2732 if (err == OK) { 2733 modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR); 2734 modifyFlags(TEXT_RUNNING, CLEAR); 2735 } 2736 } 2737 return err; 2738} 2739 2740size_t AwesomePlayer::countTracks() const { 2741 return mExtractor->countTracks() + mTextDriver->countExternalTracks(); 2742} 2743 2744status_t AwesomePlayer::setVideoScalingMode(int32_t mode) { 2745 Mutex::Autolock lock(mLock); 2746 return setVideoScalingMode_l(mode); 2747} 2748 2749status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) { 2750 mVideoScalingMode = mode; 2751 if (mNativeWindow != NULL) { 2752 status_t err = native_window_set_scaling_mode( 2753 mNativeWindow.get(), mVideoScalingMode); 2754 if (err != OK) { 2755 ALOGW("Failed to set scaling mode: %d", err); 2756 } 2757 return err; 2758 } 2759 return OK; 2760} 2761 2762status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) { 2763 ATRACE_CALL(); 2764 if (NULL == reply) { 2765 return android::BAD_VALUE; 2766 } 2767 int32_t methodId; 2768 status_t ret = request.readInt32(&methodId); 2769 if (ret != android::OK) { 2770 return ret; 2771 } 2772 switch(methodId) { 2773 case INVOKE_ID_SET_VIDEO_SCALING_MODE: 2774 { 2775 int mode = request.readInt32(); 2776 return setVideoScalingMode(mode); 2777 } 2778 2779 case INVOKE_ID_GET_TRACK_INFO: 2780 { 2781 return getTrackInfo(reply); 2782 } 2783 case INVOKE_ID_ADD_EXTERNAL_SOURCE: 2784 { 2785 Mutex::Autolock autoLock(mLock); 2786 if (mTextDriver == NULL) { 2787 mTextDriver = new TimedTextDriver(mListener); 2788 } 2789 // String values written in Parcel are UTF-16 values. 2790 String8 uri(request.readString16()); 2791 String8 mimeType(request.readString16()); 2792 size_t nTracks = countTracks(); 2793 return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType); 2794 } 2795 case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD: 2796 { 2797 Mutex::Autolock autoLock(mLock); 2798 if (mTextDriver == NULL) { 2799 mTextDriver = new TimedTextDriver(mListener); 2800 } 2801 int fd = request.readFileDescriptor(); 2802 off64_t offset = request.readInt64(); 2803 off64_t length = request.readInt64(); 2804 String8 mimeType(request.readString16()); 2805 size_t nTracks = countTracks(); 2806 return mTextDriver->addOutOfBandTextSource( 2807 nTracks, fd, offset, length, mimeType); 2808 } 2809 case INVOKE_ID_SELECT_TRACK: 2810 { 2811 int trackIndex = request.readInt32(); 2812 return selectTrack(trackIndex, true /* select */); 2813 } 2814 case INVOKE_ID_UNSELECT_TRACK: 2815 { 2816 int trackIndex = request.readInt32(); 2817 return selectTrack(trackIndex, false /* select */); 2818 } 2819 default: 2820 { 2821 return ERROR_UNSUPPORTED; 2822 } 2823 } 2824 // It will not reach here. 2825 return OK; 2826} 2827 2828bool AwesomePlayer::isStreamingHTTP() const { 2829 return mCachedSource != NULL || mWVMExtractor != NULL; 2830} 2831 2832status_t AwesomePlayer::dump( 2833 int fd, const Vector<String16> & /* args */) const { 2834 Mutex::Autolock autoLock(mStatsLock); 2835 2836 FILE *out = fdopen(dup(fd), "w"); 2837 2838 fprintf(out, " AwesomePlayer\n"); 2839 if (mStats.mFd < 0) { 2840 fprintf(out, " URI(suppressed)"); 2841 } else { 2842 fprintf(out, " fd(%d)", mStats.mFd); 2843 } 2844 2845 fprintf(out, ", flags(0x%08x)", mStats.mFlags); 2846 2847 if (mStats.mBitrate >= 0) { 2848 fprintf(out, ", bitrate(%" PRId64 " bps)", mStats.mBitrate); 2849 } 2850 2851 fprintf(out, "\n"); 2852 2853 for (size_t i = 0; i < mStats.mTracks.size(); ++i) { 2854 const TrackStat &stat = mStats.mTracks.itemAt(i); 2855 2856 fprintf(out, " Track %zu\n", i + 1); 2857 fprintf(out, " MIME(%s)", stat.mMIME.string()); 2858 2859 if (!stat.mDecoderName.isEmpty()) { 2860 fprintf(out, ", decoder(%s)", stat.mDecoderName.string()); 2861 } 2862 2863 fprintf(out, "\n"); 2864 2865 if ((ssize_t)i == mStats.mVideoTrackIndex) { 2866 fprintf(out, 2867 " videoDimensions(%d x %d), " 2868 "numVideoFramesDecoded(%" PRId64 "), " 2869 "numVideoFramesDropped(%" PRId64 ")\n", 2870 mStats.mVideoWidth, 2871 mStats.mVideoHeight, 2872 mStats.mNumVideoFramesDecoded, 2873 mStats.mNumVideoFramesDropped); 2874 } 2875 } 2876 2877 fclose(out); 2878 out = NULL; 2879 2880 return OK; 2881} 2882 2883void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) { 2884 switch (mode) { 2885 case SET: 2886 mFlags |= value; 2887 break; 2888 case CLEAR: 2889 if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) { 2890 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 2891 } 2892 mFlags &= ~value; 2893 break; 2894 case ASSIGN: 2895 mFlags = value; 2896 break; 2897 default: 2898 TRESPASS(); 2899 } 2900 2901 { 2902 Mutex::Autolock autoLock(mStatsLock); 2903 mStats.mFlags = mFlags; 2904 } 2905} 2906 2907void AwesomePlayer::onAudioTearDownEvent() { 2908 2909 Mutex::Autolock autoLock(mLock); 2910 if (!mAudioTearDownEventPending) { 2911 return; 2912 } 2913 mAudioTearDownEventPending = false; 2914 2915 ALOGV("onAudioTearDownEvent"); 2916 2917 // stream info is cleared by reset_l() so copy what we need 2918 mAudioTearDownWasPlaying = (mFlags & PLAYING); 2919 KeyedVector<String8, String8> uriHeaders(mUriHeaders); 2920 sp<DataSource> fileSource(mFileSource); 2921 2922 mStatsLock.lock(); 2923 String8 uri(mStats.mURI); 2924 mStatsLock.unlock(); 2925 2926 // get current position so we can start recreated stream from here 2927 getPosition(&mAudioTearDownPosition); 2928 2929 // Reset and recreate 2930 reset_l(); 2931 2932 status_t err; 2933 2934 if (fileSource != NULL) { 2935 mFileSource = fileSource; 2936 err = setDataSource_l(fileSource); 2937 } else { 2938 err = setDataSource_l(uri, &uriHeaders); 2939 } 2940 2941 mFlags |= PREPARING; 2942 if ( err != OK ) { 2943 // This will force beingPrepareAsync_l() to notify 2944 // a MEDIA_ERROR to the client and abort the prepare 2945 mFlags |= PREPARE_CANCELLED; 2946 } 2947 2948 mAudioTearDown = true; 2949 mIsAsyncPrepare = true; 2950 2951 // Call prepare for the host decoding 2952 beginPrepareAsync_l(); 2953} 2954 2955} // namespace android 2956