AwesomePlayer.cpp revision 1b78c4b1484c7d4c12b9a87329dc8d4b6e8c0c37
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 1867 if (mFlags & FIRST_FRAME) { 1868 modifyFlags(FIRST_FRAME, CLEAR); 1869 mSinceLastDropped = 0; 1870 mClockEstimator->reset(); 1871 mTimeSourceDeltaUs = estimateRealTimeUs(ts, systemTimeUs) - timeUs; 1872 } 1873 1874 int64_t realTimeUs, mediaTimeUs; 1875 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL 1876 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 1877 ALOGV("updating TSdelta (%" PRId64 " => %" PRId64 " change %" PRId64 ")", 1878 mTimeSourceDeltaUs, realTimeUs - mediaTimeUs, 1879 mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)); 1880 ATRACE_INT("TS delta change (ms)", (mTimeSourceDeltaUs - (realTimeUs - mediaTimeUs)) / 1E3); 1881 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 1882 } 1883 1884 if (wasSeeking == SEEK_VIDEO_ONLY) { 1885 int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs; 1886 1887 int64_t latenessUs = nowUs - timeUs; 1888 1889 ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); 1890 1891 if (latenessUs > 0) { 1892 ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6); 1893 } 1894 } 1895 1896 if (wasSeeking == NO_SEEK) { 1897 // Let's display the first frame after seeking right away. 1898 1899 int64_t nowUs = estimateRealTimeUs(ts, systemTimeUs) - mTimeSourceDeltaUs; 1900 1901 int64_t latenessUs = nowUs - timeUs; 1902 1903 ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); 1904 1905 if (latenessUs > 500000ll 1906 && mAudioPlayer != NULL 1907 && mAudioPlayer->getMediaTimeMapping( 1908 &realTimeUs, &mediaTimeUs)) { 1909 if (mWVMExtractor == NULL) { 1910 ALOGI("we're much too late (%.2f secs), video skipping ahead", 1911 latenessUs / 1E6); 1912 1913 mVideoBuffer->release(); 1914 mVideoBuffer = NULL; 1915 1916 mSeeking = SEEK_VIDEO_ONLY; 1917 mSeekTimeUs = mediaTimeUs; 1918 1919 postVideoEvent_l(); 1920 return; 1921 } else { 1922 // The widevine extractor doesn't deal well with seeking 1923 // audio and video independently. We'll just have to wait 1924 // until the decoder catches up, which won't be long at all. 1925 ALOGI("we're very late (%.2f secs)", latenessUs / 1E6); 1926 } 1927 } 1928 1929 if (latenessUs > 40000) { 1930 // We're more than 40ms late. 1931 ALOGV("we're late by %lld us (%.2f secs)", 1932 latenessUs, latenessUs / 1E6); 1933 1934 if (!(mFlags & SLOW_DECODER_HACK) 1935 || mSinceLastDropped > FRAME_DROP_FREQ) 1936 { 1937 ALOGV("we're late by %lld us (%.2f secs) dropping " 1938 "one after %d frames", 1939 latenessUs, latenessUs / 1E6, mSinceLastDropped); 1940 1941 mSinceLastDropped = 0; 1942 mVideoBuffer->release(); 1943 mVideoBuffer = NULL; 1944 1945 { 1946 Mutex::Autolock autoLock(mStatsLock); 1947 ++mStats.mNumVideoFramesDropped; 1948 } 1949 1950 postVideoEvent_l(0); 1951 return; 1952 } 1953 } 1954 1955 if (latenessUs < -10000) { 1956 // We're more than 10ms early. Try to schedule at least 12ms 1957 // early (to hit this same check), or just on time. 1958 postVideoEvent_l(latenessUs < -22000 ? 10000 : -latenessUs); 1959 return; 1960 } 1961 } 1962 1963 if ((mNativeWindow != NULL) 1964 && (mVideoRendererIsPreview || mVideoRenderer == NULL)) { 1965 mVideoRendererIsPreview = false; 1966 1967 initRenderer_l(); 1968 } 1969 1970 if (mVideoRenderer != NULL) { 1971 mSinceLastDropped++; 1972 mVideoRenderer->render(mVideoBuffer); 1973 if (!mVideoRenderingStarted) { 1974 mVideoRenderingStarted = true; 1975 notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START); 1976 } 1977 1978 if (mFlags & PLAYING) { 1979 notifyIfMediaStarted_l(); 1980 } 1981 } 1982 1983 mVideoBuffer->release(); 1984 mVideoBuffer = NULL; 1985 1986 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) { 1987 modifyFlags(SEEK_PREVIEW, CLEAR); 1988 return; 1989 } 1990 1991 /* get next frame time */ 1992 if (wasSeeking == NO_SEEK) { 1993 MediaSource::ReadOptions options; 1994 for (;;) { 1995 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1996 if (err != OK) { 1997 // deal with any errors next time 1998 CHECK(mVideoBuffer == NULL); 1999 postVideoEvent_l(0); 2000 return; 2001 } 2002 2003 if (mVideoBuffer->range_length() != 0) { 2004 break; 2005 } 2006 2007 // Some decoders, notably the PV AVC software decoder 2008 // return spurious empty buffers that we just want to ignore. 2009 2010 mVideoBuffer->release(); 2011 mVideoBuffer = NULL; 2012 } 2013 2014 { 2015 Mutex::Autolock autoLock(mStatsLock); 2016 ++mStats.mNumVideoFramesDecoded; 2017 } 2018 2019 int64_t nextTimeUs; 2020 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &nextTimeUs)); 2021 systemTimeUs = mSystemTimeSource.getRealTimeUs(); 2022 int64_t delayUs = nextTimeUs - estimateRealTimeUs(ts, systemTimeUs) + mTimeSourceDeltaUs; 2023 ATRACE_INT("Frame delta (ms)", (nextTimeUs - timeUs) / 1E3); 2024 ALOGV("next frame in %" PRId64, delayUs); 2025 // try to schedule at least 12ms before due time, or just on time 2026 postVideoEvent_l(delayUs > 22000 ? 10000 : delayUs < 0 ? 0 : delayUs); 2027 return; 2028 } 2029 2030 postVideoEvent_l(); 2031} 2032 2033int64_t AwesomePlayer::estimateRealTimeUs(TimeSource *ts, int64_t systemTimeUs) { 2034 if (ts == &mSystemTimeSource) { 2035 return systemTimeUs; 2036 } else { 2037 return (int64_t)mClockEstimator->estimate(systemTimeUs, ts->getRealTimeUs()); 2038 } 2039} 2040 2041void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 2042 ATRACE_CALL(); 2043 2044 if (mVideoEventPending) { 2045 return; 2046 } 2047 2048 mVideoEventPending = true; 2049 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 2050} 2051 2052void AwesomePlayer::postStreamDoneEvent_l(status_t status) { 2053 if (mStreamDoneEventPending) { 2054 return; 2055 } 2056 mStreamDoneEventPending = true; 2057 2058 mStreamDoneStatus = status; 2059 mQueue.postEvent(mStreamDoneEvent); 2060} 2061 2062void AwesomePlayer::postBufferingEvent_l() { 2063 if (mBufferingEventPending) { 2064 return; 2065 } 2066 mBufferingEventPending = true; 2067 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); 2068} 2069 2070void AwesomePlayer::postVideoLagEvent_l() { 2071 if (mVideoLagEventPending) { 2072 return; 2073 } 2074 mVideoLagEventPending = true; 2075 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); 2076} 2077 2078void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) { 2079 Mutex::Autolock autoLock(mAudioLock); 2080 if (mAudioStatusEventPending) { 2081 return; 2082 } 2083 mAudioStatusEventPending = true; 2084 // Do not honor delay when looping in order to limit audio gap 2085 if (mFlags & (LOOPING | AUTO_LOOPING)) { 2086 delayUs = 0; 2087 } 2088 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs); 2089} 2090 2091void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) { 2092 Mutex::Autolock autoLock(mAudioLock); 2093 if (mAudioTearDownEventPending) { 2094 return; 2095 } 2096 mAudioTearDownEventPending = true; 2097 mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs); 2098} 2099 2100void AwesomePlayer::onCheckAudioStatus() { 2101 { 2102 Mutex::Autolock autoLock(mAudioLock); 2103 if (!mAudioStatusEventPending) { 2104 // Event was dispatched and while we were blocking on the mutex, 2105 // has already been cancelled. 2106 return; 2107 } 2108 2109 mAudioStatusEventPending = false; 2110 } 2111 2112 Mutex::Autolock autoLock(mLock); 2113 2114 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { 2115 mWatchForAudioSeekComplete = false; 2116 2117 if (!mSeekNotificationSent) { 2118 notifyListener_l(MEDIA_SEEK_COMPLETE); 2119 mSeekNotificationSent = true; 2120 } 2121 2122 if (mVideoSource == NULL) { 2123 // For video the mSeeking flag is always reset in finishSeekIfNecessary 2124 mSeeking = NO_SEEK; 2125 } 2126 2127 notifyIfMediaStarted_l(); 2128 } 2129 2130 status_t finalStatus; 2131 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) { 2132 mWatchForAudioEOS = false; 2133 modifyFlags(AUDIO_AT_EOS, SET); 2134 modifyFlags(FIRST_FRAME, SET); 2135 postStreamDoneEvent_l(finalStatus); 2136 } 2137} 2138 2139status_t AwesomePlayer::prepare() { 2140 ATRACE_CALL(); 2141 Mutex::Autolock autoLock(mLock); 2142 return prepare_l(); 2143} 2144 2145status_t AwesomePlayer::prepare_l() { 2146 if (mFlags & PREPARED) { 2147 return OK; 2148 } 2149 2150 if (mFlags & PREPARING) { 2151 return UNKNOWN_ERROR; 2152 } 2153 2154 mIsAsyncPrepare = false; 2155 status_t err = prepareAsync_l(); 2156 2157 if (err != OK) { 2158 return err; 2159 } 2160 2161 while (mFlags & PREPARING) { 2162 mPreparedCondition.wait(mLock); 2163 } 2164 2165 return mPrepareResult; 2166} 2167 2168status_t AwesomePlayer::prepareAsync() { 2169 ATRACE_CALL(); 2170 Mutex::Autolock autoLock(mLock); 2171 2172 if (mFlags & PREPARING) { 2173 return UNKNOWN_ERROR; // async prepare already pending 2174 } 2175 2176 mIsAsyncPrepare = true; 2177 return prepareAsync_l(); 2178} 2179 2180status_t AwesomePlayer::prepareAsync_l() { 2181 if (mFlags & PREPARING) { 2182 return UNKNOWN_ERROR; // async prepare already pending 2183 } 2184 2185 if (!mQueueStarted) { 2186 mQueue.start(); 2187 mQueueStarted = true; 2188 } 2189 2190 modifyFlags(PREPARING, SET); 2191 mAsyncPrepareEvent = new AwesomeEvent( 2192 this, &AwesomePlayer::onPrepareAsyncEvent); 2193 2194 mQueue.postEvent(mAsyncPrepareEvent); 2195 2196 return OK; 2197} 2198 2199status_t AwesomePlayer::finishSetDataSource_l() { 2200 ATRACE_CALL(); 2201 sp<DataSource> dataSource; 2202 2203 bool isWidevineStreaming = false; 2204 if (!strncasecmp("widevine://", mUri.string(), 11)) { 2205 isWidevineStreaming = true; 2206 2207 String8 newURI = String8("http://"); 2208 newURI.append(mUri.string() + 11); 2209 2210 mUri = newURI; 2211 } 2212 2213 AString sniffedMIME; 2214 2215 if (!strncasecmp("http://", mUri.string(), 7) 2216 || !strncasecmp("https://", mUri.string(), 8) 2217 || isWidevineStreaming) { 2218 mConnectingDataSource = HTTPBase::Create( 2219 (mFlags & INCOGNITO) 2220 ? HTTPBase::kFlagIncognito 2221 : 0); 2222 2223 if (mUIDValid) { 2224 mConnectingDataSource->setUID(mUID); 2225 } 2226 2227 String8 cacheConfig; 2228 bool disconnectAtHighwatermark; 2229 NuCachedSource2::RemoveCacheSpecificHeaders( 2230 &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark); 2231 2232 mLock.unlock(); 2233 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); 2234 mLock.lock(); 2235 2236 if (err != OK) { 2237 mConnectingDataSource.clear(); 2238 2239 ALOGI("mConnectingDataSource->connect() returned %d", err); 2240 return err; 2241 } 2242 2243 if (!isWidevineStreaming) { 2244 // The widevine extractor does its own caching. 2245 2246#if 0 2247 mCachedSource = new NuCachedSource2( 2248 new ThrottledSource( 2249 mConnectingDataSource, 50 * 1024 /* bytes/sec */)); 2250#else 2251 mCachedSource = new NuCachedSource2( 2252 mConnectingDataSource, 2253 cacheConfig.isEmpty() ? NULL : cacheConfig.string(), 2254 disconnectAtHighwatermark); 2255#endif 2256 2257 dataSource = mCachedSource; 2258 } else { 2259 dataSource = mConnectingDataSource; 2260 } 2261 2262 mConnectingDataSource.clear(); 2263 2264 String8 contentType = dataSource->getMIMEType(); 2265 2266 if (strncasecmp(contentType.string(), "audio/", 6)) { 2267 // We're not doing this for streams that appear to be audio-only 2268 // streams to ensure that even low bandwidth streams start 2269 // playing back fairly instantly. 2270 2271 // We're going to prefill the cache before trying to instantiate 2272 // the extractor below, as the latter is an operation that otherwise 2273 // could block on the datasource for a significant amount of time. 2274 // During that time we'd be unable to abort the preparation phase 2275 // without this prefill. 2276 if (mCachedSource != NULL) { 2277 // We're going to prefill the cache before trying to instantiate 2278 // the extractor below, as the latter is an operation that otherwise 2279 // could block on the datasource for a significant amount of time. 2280 // During that time we'd be unable to abort the preparation phase 2281 // without this prefill. 2282 2283 mLock.unlock(); 2284 2285 // Initially make sure we have at least 192 KB for the sniff 2286 // to complete without blocking. 2287 static const size_t kMinBytesForSniffing = 192 * 1024; 2288 2289 off64_t metaDataSize = -1ll; 2290 for (;;) { 2291 status_t finalStatus; 2292 size_t cachedDataRemaining = 2293 mCachedSource->approxDataRemaining(&finalStatus); 2294 2295 if (finalStatus != OK 2296 || (metaDataSize >= 0 2297 && cachedDataRemaining >= metaDataSize) 2298 || (mFlags & PREPARE_CANCELLED)) { 2299 break; 2300 } 2301 2302 ALOGV("now cached %d bytes of data", cachedDataRemaining); 2303 2304 if (metaDataSize < 0 2305 && cachedDataRemaining >= kMinBytesForSniffing) { 2306 String8 tmp; 2307 float confidence; 2308 sp<AMessage> meta; 2309 if (!dataSource->sniff(&tmp, &confidence, &meta)) { 2310 mLock.lock(); 2311 return UNKNOWN_ERROR; 2312 } 2313 2314 // We successfully identified the file's extractor to 2315 // be, remember this mime type so we don't have to 2316 // sniff it again when we call MediaExtractor::Create() 2317 // below. 2318 sniffedMIME = tmp.string(); 2319 2320 if (meta == NULL 2321 || !meta->findInt64("meta-data-size", 2322 reinterpret_cast<int64_t*>(&metaDataSize))) { 2323 metaDataSize = kHighWaterMarkBytes; 2324 } 2325 2326 CHECK_GE(metaDataSize, 0ll); 2327 ALOGV("metaDataSize = %lld bytes", metaDataSize); 2328 } 2329 2330 usleep(200000); 2331 } 2332 2333 mLock.lock(); 2334 } 2335 2336 if (mFlags & PREPARE_CANCELLED) { 2337 ALOGI("Prepare cancelled while waiting for initial cache fill."); 2338 return UNKNOWN_ERROR; 2339 } 2340 } 2341 } else { 2342 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); 2343 } 2344 2345 if (dataSource == NULL) { 2346 return UNKNOWN_ERROR; 2347 } 2348 2349 sp<MediaExtractor> extractor; 2350 2351 if (isWidevineStreaming) { 2352 String8 mimeType; 2353 float confidence; 2354 sp<AMessage> dummy; 2355 bool success; 2356 2357 // SniffWVM is potentially blocking since it may require network access. 2358 // Do not call it with mLock held. 2359 mLock.unlock(); 2360 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 2361 mLock.lock(); 2362 2363 if (!success 2364 || strcasecmp( 2365 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 2366 return ERROR_UNSUPPORTED; 2367 } 2368 2369 mWVMExtractor = new WVMExtractor(dataSource); 2370 mWVMExtractor->setAdaptiveStreamingMode(true); 2371 if (mUIDValid) 2372 mWVMExtractor->setUID(mUID); 2373 extractor = mWVMExtractor; 2374 } else { 2375 extractor = MediaExtractor::Create( 2376 dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); 2377 2378 if (extractor == NULL) { 2379 return UNKNOWN_ERROR; 2380 } 2381 } 2382 2383 if (extractor->getDrmFlag()) { 2384 checkDrmStatus(dataSource); 2385 } 2386 2387 status_t err = setDataSource_l(extractor); 2388 2389 if (err != OK) { 2390 mWVMExtractor.clear(); 2391 2392 return err; 2393 } 2394 2395 return OK; 2396} 2397 2398void AwesomePlayer::abortPrepare(status_t err) { 2399 CHECK(err != OK); 2400 2401 if (mIsAsyncPrepare) { 2402 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 2403 } 2404 2405 mPrepareResult = err; 2406 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2407 mAsyncPrepareEvent = NULL; 2408 mPreparedCondition.broadcast(); 2409 mAudioTearDown = false; 2410} 2411 2412// static 2413bool AwesomePlayer::ContinuePreparation(void *cookie) { 2414 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie); 2415 2416 return (me->mFlags & PREPARE_CANCELLED) == 0; 2417} 2418 2419void AwesomePlayer::onPrepareAsyncEvent() { 2420 Mutex::Autolock autoLock(mLock); 2421 beginPrepareAsync_l(); 2422} 2423 2424void AwesomePlayer::beginPrepareAsync_l() { 2425 if (mFlags & PREPARE_CANCELLED) { 2426 ALOGI("prepare was cancelled before doing anything"); 2427 abortPrepare(UNKNOWN_ERROR); 2428 return; 2429 } 2430 2431 if (mUri.size() > 0) { 2432 status_t err = finishSetDataSource_l(); 2433 2434 if (err != OK) { 2435 abortPrepare(err); 2436 return; 2437 } 2438 } 2439 2440 if (mVideoTrack != NULL && mVideoSource == NULL) { 2441 status_t err = initVideoDecoder(); 2442 2443 if (err != OK) { 2444 abortPrepare(err); 2445 return; 2446 } 2447 } 2448 2449 if (mAudioTrack != NULL && mAudioSource == NULL) { 2450 status_t err = initAudioDecoder(); 2451 2452 if (err != OK) { 2453 abortPrepare(err); 2454 return; 2455 } 2456 } 2457 2458 modifyFlags(PREPARING_CONNECTED, SET); 2459 2460 if (isStreamingHTTP()) { 2461 postBufferingEvent_l(); 2462 } else { 2463 finishAsyncPrepare_l(); 2464 } 2465} 2466 2467void AwesomePlayer::finishAsyncPrepare_l() { 2468 if (mIsAsyncPrepare) { 2469 if (mVideoSource == NULL) { 2470 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); 2471 } else { 2472 notifyVideoSize_l(); 2473 } 2474 2475 notifyListener_l(MEDIA_PREPARED); 2476 } 2477 2478 mPrepareResult = OK; 2479 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2480 modifyFlags(PREPARED, SET); 2481 mAsyncPrepareEvent = NULL; 2482 mPreparedCondition.broadcast(); 2483 2484 if (mAudioTearDown) { 2485 if (mPrepareResult == OK) { 2486 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 2487 seekTo_l(mAudioTearDownPosition); 2488 } 2489 2490 if (mAudioTearDownWasPlaying) { 2491 modifyFlags(CACHE_UNDERRUN, CLEAR); 2492 play_l(); 2493 } 2494 } 2495 mAudioTearDown = false; 2496 } 2497} 2498 2499uint32_t AwesomePlayer::flags() const { 2500 return mExtractorFlags; 2501} 2502 2503void AwesomePlayer::postAudioEOS(int64_t delayUs) { 2504 postCheckAudioStatusEvent(delayUs); 2505} 2506 2507void AwesomePlayer::postAudioSeekComplete() { 2508 postCheckAudioStatusEvent(0); 2509} 2510 2511void AwesomePlayer::postAudioTearDown() { 2512 postAudioTearDownEvent(0); 2513} 2514 2515status_t AwesomePlayer::setParameter(int key, const Parcel &request) { 2516 switch (key) { 2517 case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS: 2518 { 2519 return setCacheStatCollectFreq(request); 2520 } 2521 case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE: 2522 { 2523 if (mAudioPlayer != NULL) { 2524 return mAudioPlayer->setPlaybackRatePermille(request.readInt32()); 2525 } else { 2526 return NO_INIT; 2527 } 2528 } 2529 default: 2530 { 2531 return ERROR_UNSUPPORTED; 2532 } 2533 } 2534} 2535 2536status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) { 2537 if (mCachedSource != NULL) { 2538 int32_t freqMs = request.readInt32(); 2539 ALOGD("Request to keep cache stats in the past %d ms", 2540 freqMs); 2541 return mCachedSource->setCacheStatCollectFreq(freqMs); 2542 } 2543 return ERROR_UNSUPPORTED; 2544} 2545 2546status_t AwesomePlayer::getParameter(int key, Parcel *reply) { 2547 switch (key) { 2548 case KEY_PARAMETER_AUDIO_CHANNEL_COUNT: 2549 { 2550 int32_t channelCount; 2551 if (mAudioTrack == 0 || 2552 !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) { 2553 channelCount = 0; 2554 } 2555 reply->writeInt32(channelCount); 2556 } 2557 return OK; 2558 default: 2559 { 2560 return ERROR_UNSUPPORTED; 2561 } 2562 } 2563} 2564 2565status_t AwesomePlayer::getTrackInfo(Parcel *reply) const { 2566 Mutex::Autolock autoLock(mLock); 2567 size_t trackCount = mExtractor->countTracks(); 2568 if (mTextDriver != NULL) { 2569 trackCount += mTextDriver->countExternalTracks(); 2570 } 2571 2572 reply->writeInt32(trackCount); 2573 for (size_t i = 0; i < mExtractor->countTracks(); ++i) { 2574 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 2575 2576 const char *_mime; 2577 CHECK(meta->findCString(kKeyMIMEType, &_mime)); 2578 2579 String8 mime = String8(_mime); 2580 2581 reply->writeInt32(2); // 2 fields 2582 2583 if (!strncasecmp(mime.string(), "video/", 6)) { 2584 reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO); 2585 } else if (!strncasecmp(mime.string(), "audio/", 6)) { 2586 reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO); 2587 } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { 2588 reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT); 2589 } else { 2590 reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN); 2591 } 2592 2593 const char *lang; 2594 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 2595 lang = "und"; 2596 } 2597 reply->writeString16(String16(lang)); 2598 } 2599 2600 if (mTextDriver != NULL) { 2601 mTextDriver->getExternalTrackInfo(reply); 2602 } 2603 return OK; 2604} 2605 2606status_t AwesomePlayer::selectAudioTrack_l( 2607 const sp<MediaSource>& source, size_t trackIndex) { 2608 2609 ALOGI("selectAudioTrack_l: trackIndex=%zu, mFlags=0x%x", trackIndex, mFlags); 2610 2611 { 2612 Mutex::Autolock autoLock(mStatsLock); 2613 if ((ssize_t)trackIndex == mActiveAudioTrackIndex) { 2614 ALOGI("Track %zu is active. Does nothing.", trackIndex); 2615 return OK; 2616 } 2617 //mStats.mFlags = mFlags; 2618 } 2619 2620 if (mSeeking != NO_SEEK) { 2621 ALOGE("Selecting a track while seeking is not supported"); 2622 return ERROR_UNSUPPORTED; 2623 } 2624 2625 if ((mFlags & PREPARED) == 0) { 2626 ALOGE("Data source has not finished preparation"); 2627 return ERROR_UNSUPPORTED; 2628 } 2629 2630 CHECK(source != NULL); 2631 bool wasPlaying = (mFlags & PLAYING) != 0; 2632 2633 pause_l(); 2634 2635 int64_t curTimeUs; 2636 CHECK_EQ(getPosition(&curTimeUs), (status_t)OK); 2637 2638 if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED)) 2639 && mAudioSource != NULL) { 2640 // If we had an audio player, it would have effectively 2641 // taken possession of the audio source and stopped it when 2642 // _it_ is stopped. Otherwise this is still our responsibility. 2643 mAudioSource->stop(); 2644 } 2645 mAudioSource.clear(); 2646 mOmxSource.clear(); 2647 2648 mTimeSource = NULL; 2649 2650 delete mAudioPlayer; 2651 mAudioPlayer = NULL; 2652 2653 modifyFlags(AUDIOPLAYER_STARTED, CLEAR); 2654 2655 setAudioSource(source); 2656 2657 modifyFlags(AUDIO_AT_EOS, CLEAR); 2658 modifyFlags(AT_EOS, CLEAR); 2659 2660 status_t err; 2661 if ((err = initAudioDecoder()) != OK) { 2662 ALOGE("Failed to init audio decoder: 0x%x", err); 2663 return err; 2664 } 2665 2666 mSeekNotificationSent = true; 2667 seekTo_l(curTimeUs); 2668 2669 if (wasPlaying) { 2670 play_l(); 2671 } 2672 2673 mActiveAudioTrackIndex = trackIndex; 2674 2675 return OK; 2676} 2677 2678status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) { 2679 ATRACE_CALL(); 2680 ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select); 2681 Mutex::Autolock autoLock(mLock); 2682 size_t trackCount = mExtractor->countTracks(); 2683 if (mTextDriver != NULL) { 2684 trackCount += mTextDriver->countExternalTracks(); 2685 } 2686 if (trackIndex >= trackCount) { 2687 ALOGE("Track index (%zu) is out of range [0, %zu)", trackIndex, trackCount); 2688 return ERROR_OUT_OF_RANGE; 2689 } 2690 2691 bool isAudioTrack = false; 2692 if (trackIndex < mExtractor->countTracks()) { 2693 sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex); 2694 const char *mime; 2695 CHECK(meta->findCString(kKeyMIMEType, &mime)); 2696 isAudioTrack = !strncasecmp(mime, "audio/", 6); 2697 2698 if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) { 2699 ALOGE("Track %zu is not either audio or timed text", trackIndex); 2700 return ERROR_UNSUPPORTED; 2701 } 2702 } 2703 2704 if (isAudioTrack) { 2705 if (!select) { 2706 ALOGE("Deselect an audio track (%zu) is not supported", trackIndex); 2707 return ERROR_UNSUPPORTED; 2708 } 2709 return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex); 2710 } 2711 2712 // Timed text track handling 2713 if (mTextDriver == NULL) { 2714 return INVALID_OPERATION; 2715 } 2716 2717 status_t err = OK; 2718 if (select) { 2719 err = mTextDriver->selectTrack(trackIndex); 2720 if (err == OK) { 2721 modifyFlags(TEXTPLAYER_INITIALIZED, SET); 2722 if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) { 2723 mTextDriver->start(); 2724 modifyFlags(TEXT_RUNNING, SET); 2725 } 2726 } 2727 } else { 2728 err = mTextDriver->unselectTrack(trackIndex); 2729 if (err == OK) { 2730 modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR); 2731 modifyFlags(TEXT_RUNNING, CLEAR); 2732 } 2733 } 2734 return err; 2735} 2736 2737size_t AwesomePlayer::countTracks() const { 2738 return mExtractor->countTracks() + mTextDriver->countExternalTracks(); 2739} 2740 2741status_t AwesomePlayer::setVideoScalingMode(int32_t mode) { 2742 Mutex::Autolock lock(mLock); 2743 return setVideoScalingMode_l(mode); 2744} 2745 2746status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) { 2747 mVideoScalingMode = mode; 2748 if (mNativeWindow != NULL) { 2749 status_t err = native_window_set_scaling_mode( 2750 mNativeWindow.get(), mVideoScalingMode); 2751 if (err != OK) { 2752 ALOGW("Failed to set scaling mode: %d", err); 2753 } 2754 return err; 2755 } 2756 return OK; 2757} 2758 2759status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) { 2760 ATRACE_CALL(); 2761 if (NULL == reply) { 2762 return android::BAD_VALUE; 2763 } 2764 int32_t methodId; 2765 status_t ret = request.readInt32(&methodId); 2766 if (ret != android::OK) { 2767 return ret; 2768 } 2769 switch(methodId) { 2770 case INVOKE_ID_SET_VIDEO_SCALING_MODE: 2771 { 2772 int mode = request.readInt32(); 2773 return setVideoScalingMode(mode); 2774 } 2775 2776 case INVOKE_ID_GET_TRACK_INFO: 2777 { 2778 return getTrackInfo(reply); 2779 } 2780 case INVOKE_ID_ADD_EXTERNAL_SOURCE: 2781 { 2782 Mutex::Autolock autoLock(mLock); 2783 if (mTextDriver == NULL) { 2784 mTextDriver = new TimedTextDriver(mListener); 2785 } 2786 // String values written in Parcel are UTF-16 values. 2787 String8 uri(request.readString16()); 2788 String8 mimeType(request.readString16()); 2789 size_t nTracks = countTracks(); 2790 return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType); 2791 } 2792 case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD: 2793 { 2794 Mutex::Autolock autoLock(mLock); 2795 if (mTextDriver == NULL) { 2796 mTextDriver = new TimedTextDriver(mListener); 2797 } 2798 int fd = request.readFileDescriptor(); 2799 off64_t offset = request.readInt64(); 2800 off64_t length = request.readInt64(); 2801 String8 mimeType(request.readString16()); 2802 size_t nTracks = countTracks(); 2803 return mTextDriver->addOutOfBandTextSource( 2804 nTracks, fd, offset, length, mimeType); 2805 } 2806 case INVOKE_ID_SELECT_TRACK: 2807 { 2808 int trackIndex = request.readInt32(); 2809 return selectTrack(trackIndex, true /* select */); 2810 } 2811 case INVOKE_ID_UNSELECT_TRACK: 2812 { 2813 int trackIndex = request.readInt32(); 2814 return selectTrack(trackIndex, false /* select */); 2815 } 2816 default: 2817 { 2818 return ERROR_UNSUPPORTED; 2819 } 2820 } 2821 // It will not reach here. 2822 return OK; 2823} 2824 2825bool AwesomePlayer::isStreamingHTTP() const { 2826 return mCachedSource != NULL || mWVMExtractor != NULL; 2827} 2828 2829status_t AwesomePlayer::dump( 2830 int fd, const Vector<String16> & /* args */) const { 2831 Mutex::Autolock autoLock(mStatsLock); 2832 2833 FILE *out = fdopen(dup(fd), "w"); 2834 2835 fprintf(out, " AwesomePlayer\n"); 2836 if (mStats.mFd < 0) { 2837 fprintf(out, " URI(suppressed)"); 2838 } else { 2839 fprintf(out, " fd(%d)", mStats.mFd); 2840 } 2841 2842 fprintf(out, ", flags(0x%08x)", mStats.mFlags); 2843 2844 if (mStats.mBitrate >= 0) { 2845 fprintf(out, ", bitrate(%" PRId64 " bps)", mStats.mBitrate); 2846 } 2847 2848 fprintf(out, "\n"); 2849 2850 for (size_t i = 0; i < mStats.mTracks.size(); ++i) { 2851 const TrackStat &stat = mStats.mTracks.itemAt(i); 2852 2853 fprintf(out, " Track %zu\n", i + 1); 2854 fprintf(out, " MIME(%s)", stat.mMIME.string()); 2855 2856 if (!stat.mDecoderName.isEmpty()) { 2857 fprintf(out, ", decoder(%s)", stat.mDecoderName.string()); 2858 } 2859 2860 fprintf(out, "\n"); 2861 2862 if ((ssize_t)i == mStats.mVideoTrackIndex) { 2863 fprintf(out, 2864 " videoDimensions(%d x %d), " 2865 "numVideoFramesDecoded(%" PRId64 "), " 2866 "numVideoFramesDropped(%" PRId64 ")\n", 2867 mStats.mVideoWidth, 2868 mStats.mVideoHeight, 2869 mStats.mNumVideoFramesDecoded, 2870 mStats.mNumVideoFramesDropped); 2871 } 2872 } 2873 2874 fclose(out); 2875 out = NULL; 2876 2877 return OK; 2878} 2879 2880void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) { 2881 switch (mode) { 2882 case SET: 2883 mFlags |= value; 2884 break; 2885 case CLEAR: 2886 if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) { 2887 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 2888 } 2889 mFlags &= ~value; 2890 break; 2891 case ASSIGN: 2892 mFlags = value; 2893 break; 2894 default: 2895 TRESPASS(); 2896 } 2897 2898 { 2899 Mutex::Autolock autoLock(mStatsLock); 2900 mStats.mFlags = mFlags; 2901 } 2902} 2903 2904void AwesomePlayer::onAudioTearDownEvent() { 2905 2906 Mutex::Autolock autoLock(mLock); 2907 if (!mAudioTearDownEventPending) { 2908 return; 2909 } 2910 mAudioTearDownEventPending = false; 2911 2912 ALOGV("onAudioTearDownEvent"); 2913 2914 // stream info is cleared by reset_l() so copy what we need 2915 mAudioTearDownWasPlaying = (mFlags & PLAYING); 2916 KeyedVector<String8, String8> uriHeaders(mUriHeaders); 2917 sp<DataSource> fileSource(mFileSource); 2918 2919 mStatsLock.lock(); 2920 String8 uri(mStats.mURI); 2921 mStatsLock.unlock(); 2922 2923 // get current position so we can start recreated stream from here 2924 getPosition(&mAudioTearDownPosition); 2925 2926 // Reset and recreate 2927 reset_l(); 2928 2929 status_t err; 2930 2931 if (fileSource != NULL) { 2932 mFileSource = fileSource; 2933 err = setDataSource_l(fileSource); 2934 } else { 2935 err = setDataSource_l(uri, &uriHeaders); 2936 } 2937 2938 mFlags |= PREPARING; 2939 if ( err != OK ) { 2940 // This will force beingPrepareAsync_l() to notify 2941 // a MEDIA_ERROR to the client and abort the prepare 2942 mFlags |= PREPARE_CANCELLED; 2943 } 2944 2945 mAudioTearDown = true; 2946 mIsAsyncPrepare = true; 2947 2948 // Call prepare for the host decoding 2949 beginPrepareAsync_l(); 2950} 2951 2952} // namespace android 2953