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