AwesomePlayer.cpp revision a0b1d4b161599c2bb2a47119e50c51e75bbe980e
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#include <utils/Log.h> 22 23#include <dlfcn.h> 24 25#include "include/ARTSPController.h" 26#include "include/AwesomePlayer.h" 27#include "include/DRMExtractor.h" 28#include "include/SoftwareRenderer.h" 29#include "include/NuCachedSource2.h" 30#include "include/ThrottledSource.h" 31#include "include/MPEG2TSExtractor.h" 32#include "include/WVMExtractor.h" 33 34#include "timedtext/TimedTextPlayer.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/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 51#include <surfaceflinger/Surface.h> 52#include <gui/ISurfaceTexture.h> 53#include <gui/SurfaceTextureClient.h> 54#include <surfaceflinger/ISurfaceComposer.h> 55 56#include <media/stagefright/foundation/ALooper.h> 57#include <media/stagefright/foundation/AMessage.h> 58 59#include <cutils/properties.h> 60 61#define USE_SURFACE_ALLOC 1 62 63namespace android { 64 65static int64_t kLowWaterMarkUs = 2000000ll; // 2secs 66static int64_t kHighWaterMarkUs = 10000000ll; // 10secs 67static int64_t kHighWaterMarkRTSPUs = 4000000ll; // 4secs 68static const size_t kLowWaterMarkBytes = 40000; 69static const size_t kHighWaterMarkBytes = 200000; 70 71struct AwesomeEvent : public TimedEventQueue::Event { 72 AwesomeEvent( 73 AwesomePlayer *player, 74 void (AwesomePlayer::*method)()) 75 : mPlayer(player), 76 mMethod(method) { 77 } 78 79protected: 80 virtual ~AwesomeEvent() {} 81 82 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { 83 (mPlayer->*mMethod)(); 84 } 85 86private: 87 AwesomePlayer *mPlayer; 88 void (AwesomePlayer::*mMethod)(); 89 90 AwesomeEvent(const AwesomeEvent &); 91 AwesomeEvent &operator=(const AwesomeEvent &); 92}; 93 94struct AwesomeLocalRenderer : public AwesomeRenderer { 95 AwesomeLocalRenderer( 96 const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta) 97 : mTarget(new SoftwareRenderer(nativeWindow, meta)) { 98 } 99 100 virtual void render(MediaBuffer *buffer) { 101 render((const uint8_t *)buffer->data() + buffer->range_offset(), 102 buffer->range_length()); 103 } 104 105 void render(const void *data, size_t size) { 106 mTarget->render(data, size, NULL); 107 } 108 109protected: 110 virtual ~AwesomeLocalRenderer() { 111 delete mTarget; 112 mTarget = NULL; 113 } 114 115private: 116 SoftwareRenderer *mTarget; 117 118 AwesomeLocalRenderer(const AwesomeLocalRenderer &); 119 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);; 120}; 121 122struct AwesomeNativeWindowRenderer : public AwesomeRenderer { 123 AwesomeNativeWindowRenderer( 124 const sp<ANativeWindow> &nativeWindow, 125 int32_t rotationDegrees) 126 : mNativeWindow(nativeWindow) { 127 applyRotation(rotationDegrees); 128 } 129 130 virtual void render(MediaBuffer *buffer) { 131 status_t err = mNativeWindow->queueBuffer( 132 mNativeWindow.get(), buffer->graphicBuffer().get()); 133 if (err != 0) { 134 LOGE("queueBuffer failed with error %s (%d)", strerror(-err), 135 -err); 136 return; 137 } 138 139 sp<MetaData> metaData = buffer->meta_data(); 140 metaData->setInt32(kKeyRendered, 1); 141 } 142 143protected: 144 virtual ~AwesomeNativeWindowRenderer() {} 145 146private: 147 sp<ANativeWindow> mNativeWindow; 148 149 void applyRotation(int32_t rotationDegrees) { 150 uint32_t transform; 151 switch (rotationDegrees) { 152 case 0: transform = 0; break; 153 case 90: transform = HAL_TRANSFORM_ROT_90; break; 154 case 180: transform = HAL_TRANSFORM_ROT_180; break; 155 case 270: transform = HAL_TRANSFORM_ROT_270; break; 156 default: transform = 0; break; 157 } 158 159 if (transform) { 160 CHECK_EQ(0, native_window_set_buffers_transform( 161 mNativeWindow.get(), transform)); 162 } 163 } 164 165 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &); 166 AwesomeNativeWindowRenderer &operator=( 167 const AwesomeNativeWindowRenderer &); 168}; 169 170// To collect the decoder usage 171void addBatteryData(uint32_t params) { 172 sp<IBinder> binder = 173 defaultServiceManager()->getService(String16("media.player")); 174 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 175 CHECK(service.get() != NULL); 176 177 service->addBatteryData(params); 178} 179 180//////////////////////////////////////////////////////////////////////////////// 181AwesomePlayer::AwesomePlayer() 182 : mQueueStarted(false), 183 mTimeSource(NULL), 184 mVideoRendererIsPreview(false), 185 mAudioPlayer(NULL), 186 mDisplayWidth(0), 187 mDisplayHeight(0), 188 mFlags(0), 189 mExtractorFlags(0), 190 mVideoBuffer(NULL), 191 mDecryptHandle(NULL), 192 mLastVideoTimeUs(-1), 193 mTextPlayer(NULL) { 194 CHECK_EQ(mClient.connect(), (status_t)OK); 195 196 DataSource::RegisterDefaultSniffers(); 197 198 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); 199 mVideoEventPending = false; 200 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone); 201 mStreamDoneEventPending = false; 202 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate); 203 mBufferingEventPending = false; 204 mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate); 205 mVideoEventPending = false; 206 207 mCheckAudioStatusEvent = new AwesomeEvent( 208 this, &AwesomePlayer::onCheckAudioStatus); 209 210 mAudioStatusEventPending = false; 211 212 reset(); 213} 214 215AwesomePlayer::~AwesomePlayer() { 216 if (mQueueStarted) { 217 mQueue.stop(); 218 } 219 220 reset(); 221 222 mClient.disconnect(); 223} 224 225void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) { 226 mQueue.cancelEvent(mVideoEvent->eventID()); 227 mVideoEventPending = false; 228 mQueue.cancelEvent(mStreamDoneEvent->eventID()); 229 mStreamDoneEventPending = false; 230 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID()); 231 mAudioStatusEventPending = false; 232 mQueue.cancelEvent(mVideoLagEvent->eventID()); 233 mVideoLagEventPending = false; 234 235 if (!keepBufferingGoing) { 236 mQueue.cancelEvent(mBufferingEvent->eventID()); 237 mBufferingEventPending = false; 238 } 239} 240 241void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) { 242 Mutex::Autolock autoLock(mLock); 243 mListener = listener; 244} 245 246status_t AwesomePlayer::setDataSource( 247 const char *uri, const KeyedVector<String8, String8> *headers) { 248 Mutex::Autolock autoLock(mLock); 249 return setDataSource_l(uri, headers); 250} 251 252status_t AwesomePlayer::setDataSource_l( 253 const char *uri, const KeyedVector<String8, String8> *headers) { 254 reset_l(); 255 256 mUri = uri; 257 258 if (headers) { 259 mUriHeaders = *headers; 260 261 ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log")); 262 if (index >= 0) { 263 // Browser is in "incognito" mode, suppress logging URLs. 264 265 // This isn't something that should be passed to the server. 266 mUriHeaders.removeItemsAt(index); 267 268 modifyFlags(INCOGNITO, SET); 269 } 270 } 271 272 if (!(mFlags & INCOGNITO)) { 273 LOGI("setDataSource_l('%s')", mUri.string()); 274 } else { 275 LOGI("setDataSource_l(URL suppressed)"); 276 } 277 278 // The actual work will be done during preparation in the call to 279 // ::finishSetDataSource_l to avoid blocking the calling thread in 280 // setDataSource for any significant time. 281 282 { 283 Mutex::Autolock autoLock(mStatsLock); 284 mStats.mFd = -1; 285 mStats.mURI = mUri; 286 } 287 288 return OK; 289} 290 291status_t AwesomePlayer::setDataSource( 292 int fd, int64_t offset, int64_t length) { 293 Mutex::Autolock autoLock(mLock); 294 295 reset_l(); 296 297 sp<DataSource> dataSource = new FileSource(fd, offset, length); 298 299 status_t err = dataSource->initCheck(); 300 301 if (err != OK) { 302 return err; 303 } 304 305 mFileSource = dataSource; 306 307 { 308 Mutex::Autolock autoLock(mStatsLock); 309 mStats.mFd = fd; 310 mStats.mURI = String8(); 311 } 312 313 return setDataSource_l(dataSource); 314} 315 316status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) { 317 return INVALID_OPERATION; 318} 319 320status_t AwesomePlayer::setDataSource_l( 321 const sp<DataSource> &dataSource) { 322 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 323 324 if (extractor == NULL) { 325 return UNKNOWN_ERROR; 326 } 327 328 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 329 if (mDecryptHandle != NULL) { 330 CHECK(mDrmManagerClient); 331 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 332 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); 333 } 334 } 335 336 return setDataSource_l(extractor); 337} 338 339status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { 340 // Attempt to approximate overall stream bitrate by summing all 341 // tracks' individual bitrates, if not all of them advertise bitrate, 342 // we have to fail. 343 344 int64_t totalBitRate = 0; 345 346 for (size_t i = 0; i < extractor->countTracks(); ++i) { 347 sp<MetaData> meta = extractor->getTrackMetaData(i); 348 349 int32_t bitrate; 350 if (!meta->findInt32(kKeyBitRate, &bitrate)) { 351 const char *mime; 352 CHECK(meta->findCString(kKeyMIMEType, &mime)); 353 LOGW("track of type '%s' does not publish bitrate", mime); 354 355 totalBitRate = -1; 356 break; 357 } 358 359 totalBitRate += bitrate; 360 } 361 362 mBitrate = totalBitRate; 363 364 LOGV("mBitrate = %lld bits/sec", mBitrate); 365 366 { 367 Mutex::Autolock autoLock(mStatsLock); 368 mStats.mBitrate = mBitrate; 369 mStats.mTracks.clear(); 370 mStats.mAudioTrackIndex = -1; 371 mStats.mVideoTrackIndex = -1; 372 } 373 374 bool haveAudio = false; 375 bool haveVideo = false; 376 for (size_t i = 0; i < extractor->countTracks(); ++i) { 377 sp<MetaData> meta = extractor->getTrackMetaData(i); 378 379 const char *mime; 380 CHECK(meta->findCString(kKeyMIMEType, &mime)); 381 382 if (!haveVideo && !strncasecmp(mime, "video/", 6)) { 383 setVideoSource(extractor->getTrack(i)); 384 haveVideo = true; 385 386 // Set the presentation/display size 387 int32_t displayWidth, displayHeight; 388 bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth); 389 if (success) { 390 success = meta->findInt32(kKeyDisplayHeight, &displayHeight); 391 } 392 if (success) { 393 mDisplayWidth = displayWidth; 394 mDisplayHeight = displayHeight; 395 } 396 397 { 398 Mutex::Autolock autoLock(mStatsLock); 399 mStats.mVideoTrackIndex = mStats.mTracks.size(); 400 mStats.mTracks.push(); 401 TrackStat *stat = 402 &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 403 stat->mMIME = mime; 404 } 405 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { 406 setAudioSource(extractor->getTrack(i)); 407 haveAudio = true; 408 409 { 410 Mutex::Autolock autoLock(mStatsLock); 411 mStats.mAudioTrackIndex = mStats.mTracks.size(); 412 mStats.mTracks.push(); 413 TrackStat *stat = 414 &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 415 stat->mMIME = mime; 416 } 417 418 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 419 // Only do this for vorbis audio, none of the other audio 420 // formats even support this ringtone specific hack and 421 // retrieving the metadata on some extractors may turn out 422 // to be very expensive. 423 sp<MetaData> fileMeta = extractor->getMetaData(); 424 int32_t loop; 425 if (fileMeta != NULL 426 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 427 modifyFlags(AUTO_LOOPING, SET); 428 } 429 } 430 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) { 431 addTextSource(extractor->getTrack(i)); 432 } 433 } 434 435 if (!haveAudio && !haveVideo) { 436 return UNKNOWN_ERROR; 437 } 438 439 mExtractorFlags = extractor->flags(); 440 441 return OK; 442} 443 444void AwesomePlayer::reset() { 445 LOGI("reset"); 446 Mutex::Autolock autoLock(mLock); 447 reset_l(); 448} 449 450void AwesomePlayer::reset_l() { 451 mDisplayWidth = 0; 452 mDisplayHeight = 0; 453 454 if (mDecryptHandle != NULL) { 455 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 456 Playback::STOP, 0); 457 mDecryptHandle = NULL; 458 mDrmManagerClient = NULL; 459 LOGI("DRM manager client stopped"); 460 } 461 462 463 if (mFlags & PLAYING) { 464 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 465 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 466 params |= IMediaPlayerService::kBatteryDataTrackAudio; 467 } 468 if (mVideoSource != NULL) { 469 params |= IMediaPlayerService::kBatteryDataTrackVideo; 470 } 471 addBatteryData(params); 472 } 473 474 if (mFlags & PREPARING) { 475 modifyFlags(PREPARE_CANCELLED, SET); 476 if (mConnectingDataSource != NULL) { 477 LOGI("interrupting the connection process"); 478 mConnectingDataSource->disconnect(); 479 } else if (mConnectingRTSPController != NULL) { 480 LOGI("interrupting the connection process"); 481 mConnectingRTSPController->disconnect(); 482 } 483 484 if (mFlags & PREPARING_CONNECTED) { 485 // We are basically done preparing, we're just buffering 486 // enough data to start playback, we can safely interrupt that. 487 finishAsyncPrepare_l(); 488 } 489 } 490 491 while (mFlags & PREPARING) { 492 mPreparedCondition.wait(mLock); 493 } 494 495 LOGI("cancel player events"); 496 cancelPlayerEvents(); 497 498 mWVMExtractor.clear(); 499 mCachedSource.clear(); 500 mAudioTrack.clear(); 501 mVideoTrack.clear(); 502 503 // Shutdown audio first, so that the respone to the reset request 504 // appears to happen instantaneously as far as the user is concerned 505 // If we did this later, audio would continue playing while we 506 // shutdown the video-related resources and the player appear to 507 // not be as responsive to a reset request. 508 if (mAudioPlayer == NULL && mAudioSource != NULL) { 509 // If we had an audio player, it would have effectively 510 // taken possession of the audio source and stopped it when 511 // _it_ is stopped. Otherwise this is still our responsibility. 512 mAudioSource->stop(); 513 } 514 mAudioSource.clear(); 515 516 mTimeSource = NULL; 517 518 delete mAudioPlayer; 519 mAudioPlayer = NULL; 520 521 if (mTextPlayer != NULL) { 522 delete mTextPlayer; 523 mTextPlayer = NULL; 524 } 525 526 mVideoRenderer.clear(); 527 528 if (mRTSPController != NULL) { 529 mRTSPController->disconnect(); 530 mRTSPController.clear(); 531 } 532 533 if (mVideoSource != NULL) { 534 shutdownVideoDecoder_l(); 535 } 536 537 mDurationUs = -1; 538 modifyFlags(0, ASSIGN); 539 mExtractorFlags = 0; 540 mTimeSourceDeltaUs = 0; 541 mVideoTimeUs = 0; 542 543 mSeeking = NO_SEEK; 544 mSeekNotificationSent = false; 545 mSeekTimeUs = 0; 546 547 mUri.setTo(""); 548 mUriHeaders.clear(); 549 550 mFileSource.clear(); 551 552 mBitrate = -1; 553 mLastVideoTimeUs = -1; 554 555 { 556 Mutex::Autolock autoLock(mStatsLock); 557 mStats.mFd = -1; 558 mStats.mURI = String8(); 559 mStats.mBitrate = -1; 560 mStats.mAudioTrackIndex = -1; 561 mStats.mVideoTrackIndex = -1; 562 mStats.mNumVideoFramesDecoded = 0; 563 mStats.mNumVideoFramesDropped = 0; 564 mStats.mVideoWidth = -1; 565 mStats.mVideoHeight = -1; 566 mStats.mFlags = 0; 567 mStats.mTracks.clear(); 568 } 569 570} 571 572void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { 573 if (mListener != NULL) { 574 sp<MediaPlayerBase> listener = mListener.promote(); 575 576 if (listener != NULL) { 577 listener->sendEvent(msg, ext1, ext2); 578 } 579 } 580} 581 582bool AwesomePlayer::getBitrate(int64_t *bitrate) { 583 off64_t size; 584 if (mDurationUs >= 0 && mCachedSource != NULL 585 && mCachedSource->getSize(&size) == OK) { 586 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec 587 return true; 588 } 589 590 if (mBitrate >= 0) { 591 *bitrate = mBitrate; 592 return true; 593 } 594 595 *bitrate = 0; 596 597 return false; 598} 599 600// Returns true iff cached duration is available/applicable. 601bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { 602 int64_t bitrate; 603 604 if (mRTSPController != NULL) { 605 *durationUs = mRTSPController->getQueueDurationUs(eos); 606 return true; 607 } else if (mCachedSource != NULL && getBitrate(&bitrate)) { 608 status_t finalStatus; 609 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 610 *durationUs = cachedDataRemaining * 8000000ll / bitrate; 611 *eos = (finalStatus != OK); 612 return true; 613 } else if (mWVMExtractor != NULL) { 614 status_t finalStatus; 615 *durationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); 616 *eos = (finalStatus != OK); 617 return true; 618 } 619 620 return false; 621} 622 623void AwesomePlayer::ensureCacheIsFetching_l() { 624 if (mCachedSource != NULL) { 625 mCachedSource->resumeFetchingIfNecessary(); 626 } 627} 628 629void AwesomePlayer::onVideoLagUpdate() { 630 Mutex::Autolock autoLock(mLock); 631 if (!mVideoLagEventPending) { 632 return; 633 } 634 mVideoLagEventPending = false; 635 636 int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs(); 637 int64_t videoLateByUs = audioTimeUs - mVideoTimeUs; 638 639 if (!(mFlags & VIDEO_AT_EOS) && videoLateByUs > 300000ll) { 640 LOGV("video late by %lld ms.", videoLateByUs / 1000ll); 641 642 notifyListener_l( 643 MEDIA_INFO, 644 MEDIA_INFO_VIDEO_TRACK_LAGGING, 645 videoLateByUs / 1000ll); 646 } 647 648 postVideoLagEvent_l(); 649} 650 651void AwesomePlayer::onBufferingUpdate() { 652 Mutex::Autolock autoLock(mLock); 653 if (!mBufferingEventPending) { 654 return; 655 } 656 mBufferingEventPending = false; 657 658 if (mCachedSource != NULL) { 659 status_t finalStatus; 660 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 661 bool eos = (finalStatus != OK); 662 663 if (eos) { 664 if (finalStatus == ERROR_END_OF_STREAM) { 665 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 666 } 667 if (mFlags & PREPARING) { 668 LOGV("cache has reached EOS, prepare is done."); 669 finishAsyncPrepare_l(); 670 } 671 } else { 672 int64_t bitrate; 673 if (getBitrate(&bitrate)) { 674 size_t cachedSize = mCachedSource->cachedSize(); 675 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; 676 677 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 678 if (percentage > 100) { 679 percentage = 100; 680 } 681 682 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 683 } else { 684 // We don't know the bitrate of the stream, use absolute size 685 // limits to maintain the cache. 686 687 if ((mFlags & PLAYING) && !eos 688 && (cachedDataRemaining < kLowWaterMarkBytes)) { 689 LOGI("cache is running low (< %d) , pausing.", 690 kLowWaterMarkBytes); 691 modifyFlags(CACHE_UNDERRUN, SET); 692 pause_l(); 693 ensureCacheIsFetching_l(); 694 sendCacheStats(); 695 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 696 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { 697 if (mFlags & CACHE_UNDERRUN) { 698 LOGI("cache has filled up (> %d), resuming.", 699 kHighWaterMarkBytes); 700 modifyFlags(CACHE_UNDERRUN, CLEAR); 701 play_l(); 702 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 703 } else if (mFlags & PREPARING) { 704 LOGV("cache has filled up (> %d), prepare is done", 705 kHighWaterMarkBytes); 706 finishAsyncPrepare_l(); 707 } 708 } 709 } 710 } 711 } else if (mWVMExtractor != NULL) { 712 status_t finalStatus; 713 714 int64_t cachedDurationUs 715 = mWVMExtractor->getCachedDurationUs(&finalStatus); 716 717 bool eos = (finalStatus != OK); 718 719 if (eos) { 720 if (finalStatus == ERROR_END_OF_STREAM) { 721 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 722 } 723 if (mFlags & PREPARING) { 724 LOGV("cache has reached EOS, prepare is done."); 725 finishAsyncPrepare_l(); 726 } 727 } else { 728 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 729 if (percentage > 100) { 730 percentage = 100; 731 } 732 733 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 734 } 735 } 736 737 int64_t cachedDurationUs; 738 bool eos; 739 if (getCachedDuration_l(&cachedDurationUs, &eos)) { 740 LOGV("cachedDurationUs = %.2f secs, eos=%d", 741 cachedDurationUs / 1E6, eos); 742 743 int64_t highWaterMarkUs = 744 (mRTSPController != NULL) ? kHighWaterMarkRTSPUs : kHighWaterMarkUs; 745 746 if ((mFlags & PLAYING) && !eos 747 && (cachedDurationUs < kLowWaterMarkUs)) { 748 LOGI("cache is running low (%.2f secs) , pausing.", 749 cachedDurationUs / 1E6); 750 modifyFlags(CACHE_UNDERRUN, SET); 751 pause_l(); 752 ensureCacheIsFetching_l(); 753 sendCacheStats(); 754 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 755 } else if (eos || cachedDurationUs > highWaterMarkUs) { 756 if (mFlags & CACHE_UNDERRUN) { 757 LOGI("cache has filled up (%.2f secs), resuming.", 758 cachedDurationUs / 1E6); 759 modifyFlags(CACHE_UNDERRUN, CLEAR); 760 play_l(); 761 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 762 } else if (mFlags & PREPARING) { 763 LOGV("cache has filled up (%.2f secs), prepare is done", 764 cachedDurationUs / 1E6); 765 finishAsyncPrepare_l(); 766 } 767 } 768 } 769 770 postBufferingEvent_l(); 771} 772 773void AwesomePlayer::sendCacheStats() { 774 sp<MediaPlayerBase> listener = mListener.promote(); 775 if (listener != NULL && mCachedSource != NULL) { 776 int32_t kbps = 0; 777 status_t err = mCachedSource->getEstimatedBandwidthKbps(&kbps); 778 if (err == OK) { 779 listener->sendEvent( 780 MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps); 781 } 782 } 783} 784 785void AwesomePlayer::onStreamDone() { 786 // Posted whenever any stream finishes playing. 787 788 Mutex::Autolock autoLock(mLock); 789 if (!mStreamDoneEventPending) { 790 return; 791 } 792 mStreamDoneEventPending = false; 793 794 if (mStreamDoneStatus != ERROR_END_OF_STREAM) { 795 LOGV("MEDIA_ERROR %d", mStreamDoneStatus); 796 797 notifyListener_l( 798 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus); 799 800 pause_l(true /* at eos */); 801 802 modifyFlags(AT_EOS, SET); 803 return; 804 } 805 806 const bool allDone = 807 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS)) 808 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS)); 809 810 if (!allDone) { 811 return; 812 } 813 814 if (mFlags & (LOOPING | AUTO_LOOPING)) { 815 seekTo_l(0); 816 817 if (mVideoSource != NULL) { 818 postVideoEvent_l(); 819 } 820 } else { 821 LOGV("MEDIA_PLAYBACK_COMPLETE"); 822 notifyListener_l(MEDIA_PLAYBACK_COMPLETE); 823 824 pause_l(true /* at eos */); 825 826 modifyFlags(AT_EOS, SET); 827 } 828} 829 830status_t AwesomePlayer::play() { 831 Mutex::Autolock autoLock(mLock); 832 833 modifyFlags(CACHE_UNDERRUN, CLEAR); 834 835 return play_l(); 836} 837 838status_t AwesomePlayer::play_l() { 839 modifyFlags(SEEK_PREVIEW, CLEAR); 840 841 if (mFlags & PLAYING) { 842 return OK; 843 } 844 845 if (!(mFlags & PREPARED)) { 846 status_t err = prepare_l(); 847 848 if (err != OK) { 849 return err; 850 } 851 } 852 853 modifyFlags(PLAYING, SET); 854 modifyFlags(FIRST_FRAME, SET); 855 856 if (mDecryptHandle != NULL) { 857 int64_t position; 858 getPosition(&position); 859 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 860 Playback::START, position / 1000); 861 } 862 863 if (mAudioSource != NULL) { 864 if (mAudioPlayer == NULL) { 865 if (mAudioSink != NULL) { 866 mAudioPlayer = new AudioPlayer(mAudioSink, this); 867 mAudioPlayer->setSource(mAudioSource); 868 869 mTimeSource = mAudioPlayer; 870 871 // If there was a seek request before we ever started, 872 // honor the request now. 873 // Make sure to do this before starting the audio player 874 // to avoid a race condition. 875 seekAudioIfNecessary_l(); 876 } 877 } 878 879 CHECK(!(mFlags & AUDIO_RUNNING)); 880 881 if (mVideoSource == NULL) { 882 status_t err = startAudioPlayer_l(); 883 884 if (err != OK) { 885 delete mAudioPlayer; 886 mAudioPlayer = NULL; 887 888 modifyFlags((PLAYING | FIRST_FRAME), CLEAR); 889 890 if (mDecryptHandle != NULL) { 891 mDrmManagerClient->setPlaybackStatus( 892 mDecryptHandle, Playback::STOP, 0); 893 } 894 895 return err; 896 } 897 } 898 } 899 900 if (mTimeSource == NULL && mAudioPlayer == NULL) { 901 mTimeSource = &mSystemTimeSource; 902 } 903 904 if (mVideoSource != NULL) { 905 // Kick off video playback 906 postVideoEvent_l(); 907 908 if (mAudioSource != NULL && mVideoSource != NULL) { 909 postVideoLagEvent_l(); 910 } 911 } 912 913 if (mFlags & AT_EOS) { 914 // Legacy behaviour, if a stream finishes playing and then 915 // is started again, we play from the start... 916 seekTo_l(0); 917 } 918 919 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted 920 | IMediaPlayerService::kBatteryDataTrackDecoder; 921 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 922 params |= IMediaPlayerService::kBatteryDataTrackAudio; 923 } 924 if (mVideoSource != NULL) { 925 params |= IMediaPlayerService::kBatteryDataTrackVideo; 926 } 927 addBatteryData(params); 928 929 return OK; 930} 931 932status_t AwesomePlayer::startAudioPlayer_l() { 933 CHECK(!(mFlags & AUDIO_RUNNING)); 934 935 if (mAudioSource == NULL || mAudioPlayer == NULL) { 936 return OK; 937 } 938 939 if (!(mFlags & AUDIOPLAYER_STARTED)) { 940 modifyFlags(AUDIOPLAYER_STARTED, SET); 941 942 bool wasSeeking = mAudioPlayer->isSeeking(); 943 944 // We've already started the MediaSource in order to enable 945 // the prefetcher to read its data. 946 status_t err = mAudioPlayer->start( 947 true /* sourceAlreadyStarted */); 948 949 if (err != OK) { 950 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 951 return err; 952 } 953 954 if (wasSeeking) { 955 CHECK(!mAudioPlayer->isSeeking()); 956 957 // We will have finished the seek while starting the audio player. 958 postAudioSeekComplete_l(); 959 } 960 } else { 961 mAudioPlayer->resume(); 962 } 963 964 modifyFlags(AUDIO_RUNNING, SET); 965 966 mWatchForAudioEOS = true; 967 968 return OK; 969} 970 971void AwesomePlayer::notifyVideoSize_l() { 972 sp<MetaData> meta = mVideoSource->getFormat(); 973 974 int32_t cropLeft, cropTop, cropRight, cropBottom; 975 if (!meta->findRect( 976 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) { 977 int32_t width, height; 978 CHECK(meta->findInt32(kKeyWidth, &width)); 979 CHECK(meta->findInt32(kKeyHeight, &height)); 980 981 cropLeft = cropTop = 0; 982 cropRight = width - 1; 983 cropBottom = height - 1; 984 985 LOGV("got dimensions only %d x %d", width, height); 986 } else { 987 LOGV("got crop rect %d, %d, %d, %d", 988 cropLeft, cropTop, cropRight, cropBottom); 989 } 990 991 int32_t displayWidth; 992 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) { 993 LOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth); 994 mDisplayWidth = displayWidth; 995 } 996 int32_t displayHeight; 997 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) { 998 LOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight); 999 mDisplayHeight = displayHeight; 1000 } 1001 1002 int32_t usableWidth = cropRight - cropLeft + 1; 1003 int32_t usableHeight = cropBottom - cropTop + 1; 1004 if (mDisplayWidth != 0) { 1005 usableWidth = mDisplayWidth; 1006 } 1007 if (mDisplayHeight != 0) { 1008 usableHeight = mDisplayHeight; 1009 } 1010 1011 { 1012 Mutex::Autolock autoLock(mStatsLock); 1013 mStats.mVideoWidth = usableWidth; 1014 mStats.mVideoHeight = usableHeight; 1015 } 1016 1017 int32_t rotationDegrees; 1018 if (!mVideoTrack->getFormat()->findInt32( 1019 kKeyRotation, &rotationDegrees)) { 1020 rotationDegrees = 0; 1021 } 1022 1023 if (rotationDegrees == 90 || rotationDegrees == 270) { 1024 notifyListener_l( 1025 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth); 1026 } else { 1027 notifyListener_l( 1028 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight); 1029 } 1030} 1031 1032void AwesomePlayer::initRenderer_l() { 1033 if (mNativeWindow == NULL) { 1034 return; 1035 } 1036 1037 sp<MetaData> meta = mVideoSource->getFormat(); 1038 1039 int32_t format; 1040 const char *component; 1041 int32_t decodedWidth, decodedHeight; 1042 CHECK(meta->findInt32(kKeyColorFormat, &format)); 1043 CHECK(meta->findCString(kKeyDecoderComponent, &component)); 1044 CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); 1045 CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); 1046 1047 int32_t rotationDegrees; 1048 if (!mVideoTrack->getFormat()->findInt32( 1049 kKeyRotation, &rotationDegrees)) { 1050 rotationDegrees = 0; 1051 } 1052 1053 mVideoRenderer.clear(); 1054 1055 // Must ensure that mVideoRenderer's destructor is actually executed 1056 // before creating a new one. 1057 IPCThreadState::self()->flushCommands(); 1058 1059 if (USE_SURFACE_ALLOC 1060 && !strncmp(component, "OMX.", 4) 1061 && strncmp(component, "OMX.google.", 11)) { 1062 // Hardware decoders avoid the CPU color conversion by decoding 1063 // directly to ANativeBuffers, so we must use a renderer that 1064 // just pushes those buffers to the ANativeWindow. 1065 mVideoRenderer = 1066 new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees); 1067 } else { 1068 // Other decoders are instantiated locally and as a consequence 1069 // allocate their buffers in local address space. This renderer 1070 // then performs a color conversion and copy to get the data 1071 // into the ANativeBuffer. 1072 mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta); 1073 } 1074} 1075 1076status_t AwesomePlayer::pause() { 1077 Mutex::Autolock autoLock(mLock); 1078 1079 modifyFlags(CACHE_UNDERRUN, CLEAR); 1080 1081 return pause_l(); 1082} 1083 1084status_t AwesomePlayer::pause_l(bool at_eos) { 1085 if (!(mFlags & PLAYING)) { 1086 return OK; 1087 } 1088 1089 cancelPlayerEvents(true /* keepBufferingGoing */); 1090 1091 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1092 if (at_eos) { 1093 // If we played the audio stream to completion we 1094 // want to make sure that all samples remaining in the audio 1095 // track's queue are played out. 1096 mAudioPlayer->pause(true /* playPendingSamples */); 1097 } else { 1098 mAudioPlayer->pause(); 1099 } 1100 1101 modifyFlags(AUDIO_RUNNING, CLEAR); 1102 } 1103 1104 if (mFlags & TEXTPLAYER_STARTED) { 1105 mTextPlayer->pause(); 1106 modifyFlags(TEXT_RUNNING, CLEAR); 1107 } 1108 1109 modifyFlags(PLAYING, CLEAR); 1110 1111 if (mDecryptHandle != NULL) { 1112 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1113 Playback::PAUSE, 0); 1114 } 1115 1116 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 1117 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 1118 params |= IMediaPlayerService::kBatteryDataTrackAudio; 1119 } 1120 if (mVideoSource != NULL) { 1121 params |= IMediaPlayerService::kBatteryDataTrackVideo; 1122 } 1123 1124 addBatteryData(params); 1125 1126 return OK; 1127} 1128 1129bool AwesomePlayer::isPlaying() const { 1130 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN); 1131} 1132 1133void AwesomePlayer::setSurface(const sp<Surface> &surface) { 1134 Mutex::Autolock autoLock(mLock); 1135 1136 mSurface = surface; 1137 setNativeWindow_l(surface); 1138} 1139 1140void AwesomePlayer::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) { 1141 Mutex::Autolock autoLock(mLock); 1142 1143 mSurface.clear(); 1144 if (surfaceTexture != NULL) { 1145 setNativeWindow_l(new SurfaceTextureClient(surfaceTexture)); 1146 } 1147} 1148 1149void AwesomePlayer::shutdownVideoDecoder_l() { 1150 if (mVideoBuffer) { 1151 mVideoBuffer->release(); 1152 mVideoBuffer = NULL; 1153 } 1154 1155 mVideoSource->stop(); 1156 1157 // The following hack is necessary to ensure that the OMX 1158 // component is completely released by the time we may try 1159 // to instantiate it again. 1160 wp<MediaSource> tmp = mVideoSource; 1161 mVideoSource.clear(); 1162 while (tmp.promote() != NULL) { 1163 usleep(1000); 1164 } 1165 IPCThreadState::self()->flushCommands(); 1166 LOGI("video decoder shutdown completed"); 1167} 1168 1169void AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) { 1170 mNativeWindow = native; 1171 1172 if (mVideoSource == NULL) { 1173 return; 1174 } 1175 1176 LOGI("attempting to reconfigure to use new surface"); 1177 1178 bool wasPlaying = (mFlags & PLAYING) != 0; 1179 1180 pause_l(); 1181 mVideoRenderer.clear(); 1182 1183 shutdownVideoDecoder_l(); 1184 1185 CHECK_EQ(initVideoDecoder(), (status_t)OK); 1186 1187 if (mLastVideoTimeUs >= 0) { 1188 mSeeking = SEEK; 1189 mSeekNotificationSent = true; 1190 mSeekTimeUs = mLastVideoTimeUs; 1191 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1192 } 1193 1194 if (wasPlaying) { 1195 play_l(); 1196 } 1197} 1198 1199void AwesomePlayer::setAudioSink( 1200 const sp<MediaPlayerBase::AudioSink> &audioSink) { 1201 Mutex::Autolock autoLock(mLock); 1202 1203 mAudioSink = audioSink; 1204} 1205 1206status_t AwesomePlayer::setLooping(bool shouldLoop) { 1207 Mutex::Autolock autoLock(mLock); 1208 1209 modifyFlags(LOOPING, CLEAR); 1210 1211 if (shouldLoop) { 1212 modifyFlags(LOOPING, SET); 1213 } 1214 1215 return OK; 1216} 1217 1218status_t AwesomePlayer::getDuration(int64_t *durationUs) { 1219 Mutex::Autolock autoLock(mMiscStateLock); 1220 1221 if (mDurationUs < 0) { 1222 return UNKNOWN_ERROR; 1223 } 1224 1225 *durationUs = mDurationUs; 1226 1227 return OK; 1228} 1229 1230status_t AwesomePlayer::getPosition(int64_t *positionUs) { 1231 if (mRTSPController != NULL) { 1232 *positionUs = mRTSPController->getNormalPlayTimeUs(); 1233 } 1234 else if (mSeeking != NO_SEEK) { 1235 *positionUs = mSeekTimeUs; 1236 } else if (mVideoSource != NULL 1237 && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) { 1238 Mutex::Autolock autoLock(mMiscStateLock); 1239 *positionUs = mVideoTimeUs; 1240 } else if (mAudioPlayer != NULL) { 1241 *positionUs = mAudioPlayer->getMediaTimeUs(); 1242 } else { 1243 *positionUs = 0; 1244 } 1245 1246 return OK; 1247} 1248 1249status_t AwesomePlayer::seekTo(int64_t timeUs) { 1250 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 1251 Mutex::Autolock autoLock(mLock); 1252 return seekTo_l(timeUs); 1253 } 1254 1255 return OK; 1256} 1257 1258status_t AwesomePlayer::setTimedTextTrackIndex(int32_t index) { 1259 if (mTextPlayer != NULL) { 1260 if (index >= 0) { // to turn on a text track 1261 status_t err = mTextPlayer->setTimedTextTrackIndex(index); 1262 if (err != OK) { 1263 return err; 1264 } 1265 1266 modifyFlags(TEXT_RUNNING, SET); 1267 modifyFlags(TEXTPLAYER_STARTED, SET); 1268 return OK; 1269 } else { // to turn off the text track display 1270 if (mFlags & TEXT_RUNNING) { 1271 modifyFlags(TEXT_RUNNING, CLEAR); 1272 } 1273 if (mFlags & TEXTPLAYER_STARTED) { 1274 modifyFlags(TEXTPLAYER_STARTED, CLEAR); 1275 } 1276 1277 return mTextPlayer->setTimedTextTrackIndex(index); 1278 } 1279 } else { 1280 return INVALID_OPERATION; 1281 } 1282} 1283 1284// static 1285void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) { 1286 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone(); 1287} 1288 1289void AwesomePlayer::onRTSPSeekDone() { 1290 notifyListener_l(MEDIA_SEEK_COMPLETE); 1291 mSeekNotificationSent = true; 1292} 1293 1294status_t AwesomePlayer::seekTo_l(int64_t timeUs) { 1295 if (mRTSPController != NULL) { 1296 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this); 1297 return OK; 1298 } 1299 1300 if (mFlags & CACHE_UNDERRUN) { 1301 modifyFlags(CACHE_UNDERRUN, CLEAR); 1302 play_l(); 1303 } 1304 1305 if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) { 1306 // Video playback completed before, there's no pending 1307 // video event right now. In order for this new seek 1308 // to be honored, we need to post one. 1309 1310 postVideoEvent_l(); 1311 } 1312 1313 mSeeking = SEEK; 1314 mSeekNotificationSent = false; 1315 mSeekTimeUs = timeUs; 1316 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1317 1318 seekAudioIfNecessary_l(); 1319 1320 if (mFlags & TEXTPLAYER_STARTED) { 1321 mTextPlayer->seekTo(mSeekTimeUs); 1322 } 1323 1324 if (!(mFlags & PLAYING)) { 1325 LOGV("seeking while paused, sending SEEK_COMPLETE notification" 1326 " immediately."); 1327 1328 notifyListener_l(MEDIA_SEEK_COMPLETE); 1329 mSeekNotificationSent = true; 1330 1331 if ((mFlags & PREPARED) && mVideoSource != NULL) { 1332 modifyFlags(SEEK_PREVIEW, SET); 1333 postVideoEvent_l(); 1334 } 1335 } 1336 1337 return OK; 1338} 1339 1340void AwesomePlayer::seekAudioIfNecessary_l() { 1341 if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) { 1342 mAudioPlayer->seekTo(mSeekTimeUs); 1343 1344 mWatchForAudioSeekComplete = true; 1345 mWatchForAudioEOS = true; 1346 1347 if (mDecryptHandle != NULL) { 1348 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1349 Playback::PAUSE, 0); 1350 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1351 Playback::START, mSeekTimeUs / 1000); 1352 } 1353 } 1354} 1355 1356void AwesomePlayer::setAudioSource(sp<MediaSource> source) { 1357 CHECK(source != NULL); 1358 1359 mAudioTrack = source; 1360} 1361 1362void AwesomePlayer::addTextSource(sp<MediaSource> source) { 1363 Mutex::Autolock autoLock(mTimedTextLock); 1364 CHECK(source != NULL); 1365 1366 if (mTextPlayer == NULL) { 1367 mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue); 1368 } 1369 1370 mTextPlayer->addTextSource(source); 1371} 1372 1373status_t AwesomePlayer::initAudioDecoder() { 1374 sp<MetaData> meta = mAudioTrack->getFormat(); 1375 1376 const char *mime; 1377 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1378 1379 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { 1380 mAudioSource = mAudioTrack; 1381 } else { 1382 mAudioSource = OMXCodec::Create( 1383 mClient.interface(), mAudioTrack->getFormat(), 1384 false, // createEncoder 1385 mAudioTrack); 1386 } 1387 1388 if (mAudioSource != NULL) { 1389 int64_t durationUs; 1390 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1391 Mutex::Autolock autoLock(mMiscStateLock); 1392 if (mDurationUs < 0 || durationUs > mDurationUs) { 1393 mDurationUs = durationUs; 1394 } 1395 } 1396 1397 status_t err = mAudioSource->start(); 1398 1399 if (err != OK) { 1400 mAudioSource.clear(); 1401 return err; 1402 } 1403 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) { 1404 // For legacy reasons we're simply going to ignore the absence 1405 // of an audio decoder for QCELP instead of aborting playback 1406 // altogether. 1407 return OK; 1408 } 1409 1410 if (mAudioSource != NULL) { 1411 Mutex::Autolock autoLock(mStatsLock); 1412 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 1413 1414 const char *component; 1415 if (!mAudioSource->getFormat() 1416 ->findCString(kKeyDecoderComponent, &component)) { 1417 component = "none"; 1418 } 1419 1420 stat->mDecoderName = component; 1421 } 1422 1423 return mAudioSource != NULL ? OK : UNKNOWN_ERROR; 1424} 1425 1426void AwesomePlayer::setVideoSource(sp<MediaSource> source) { 1427 CHECK(source != NULL); 1428 1429 mVideoTrack = source; 1430} 1431 1432status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { 1433 1434 // Either the application or the DRM system can independently say 1435 // that there must be a hardware-protected path to an external video sink. 1436 // For now we always require a hardware-protected path to external video sink 1437 // if content is DRMed, but eventually this could be optional per DRM agent. 1438 // When the application wants protection, then 1439 // (USE_SURFACE_ALLOC && (mSurface != 0) && 1440 // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp)) 1441 // will be true, but that part is already handled by SurfaceFlinger. 1442 1443#ifdef DEBUG_HDCP 1444 // For debugging, we allow a system property to control the protected usage. 1445 // In case of uninitialized or unexpected property, we default to "DRM only". 1446 bool setProtectionBit = false; 1447 char value[PROPERTY_VALUE_MAX]; 1448 if (property_get("persist.sys.hdcp_checking", value, NULL)) { 1449 if (!strcmp(value, "never")) { 1450 // nop 1451 } else if (!strcmp(value, "always")) { 1452 setProtectionBit = true; 1453 } else if (!strcmp(value, "drm-only")) { 1454 if (mDecryptHandle != NULL) { 1455 setProtectionBit = true; 1456 } 1457 // property value is empty, or unexpected value 1458 } else { 1459 if (mDecryptHandle != NULL) { 1460 setProtectionBit = true; 1461 } 1462 } 1463 // can' read property value 1464 } else { 1465 if (mDecryptHandle != NULL) { 1466 setProtectionBit = true; 1467 } 1468 } 1469 // note that usage bit is already cleared, so no need to clear it in the "else" case 1470 if (setProtectionBit) { 1471 flags |= OMXCodec::kEnableGrallocUsageProtected; 1472 } 1473#else 1474 if (mDecryptHandle != NULL) { 1475 flags |= OMXCodec::kEnableGrallocUsageProtected; 1476 } 1477#endif 1478 LOGV("initVideoDecoder flags=0x%x", flags); 1479 mVideoSource = OMXCodec::Create( 1480 mClient.interface(), mVideoTrack->getFormat(), 1481 false, // createEncoder 1482 mVideoTrack, 1483 NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL); 1484 1485 if (mVideoSource != NULL) { 1486 int64_t durationUs; 1487 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1488 Mutex::Autolock autoLock(mMiscStateLock); 1489 if (mDurationUs < 0 || durationUs > mDurationUs) { 1490 mDurationUs = durationUs; 1491 } 1492 } 1493 1494 status_t err = mVideoSource->start(); 1495 1496 if (err != OK) { 1497 mVideoSource.clear(); 1498 return err; 1499 } 1500 } 1501 1502 if (mVideoSource != NULL) { 1503 Mutex::Autolock autoLock(mStatsLock); 1504 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 1505 1506 const char *component; 1507 CHECK(mVideoSource->getFormat() 1508 ->findCString(kKeyDecoderComponent, &component)); 1509 1510 stat->mDecoderName = component; 1511 } 1512 1513 return mVideoSource != NULL ? OK : UNKNOWN_ERROR; 1514} 1515 1516void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { 1517 if (mSeeking == SEEK_VIDEO_ONLY) { 1518 mSeeking = NO_SEEK; 1519 return; 1520 } 1521 1522 if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) { 1523 return; 1524 } 1525 1526 if (mAudioPlayer != NULL) { 1527 LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6); 1528 1529 // If we don't have a video time, seek audio to the originally 1530 // requested seek time instead. 1531 1532 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs); 1533 mWatchForAudioSeekComplete = true; 1534 mWatchForAudioEOS = true; 1535 } else if (!mSeekNotificationSent) { 1536 // If we're playing video only, report seek complete now, 1537 // otherwise audio player will notify us later. 1538 notifyListener_l(MEDIA_SEEK_COMPLETE); 1539 mSeekNotificationSent = true; 1540 } 1541 1542 modifyFlags(FIRST_FRAME, SET); 1543 mSeeking = NO_SEEK; 1544 1545 if (mDecryptHandle != NULL) { 1546 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1547 Playback::PAUSE, 0); 1548 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1549 Playback::START, videoTimeUs / 1000); 1550 } 1551} 1552 1553void AwesomePlayer::onVideoEvent() { 1554 Mutex::Autolock autoLock(mLock); 1555 if (!mVideoEventPending) { 1556 // The event has been cancelled in reset_l() but had already 1557 // been scheduled for execution at that time. 1558 return; 1559 } 1560 mVideoEventPending = false; 1561 1562 if (mSeeking != NO_SEEK) { 1563 if (mVideoBuffer) { 1564 mVideoBuffer->release(); 1565 mVideoBuffer = NULL; 1566 } 1567 1568 if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL 1569 && !(mFlags & SEEK_PREVIEW)) { 1570 // We're going to seek the video source first, followed by 1571 // the audio source. 1572 // In order to avoid jumps in the DataSource offset caused by 1573 // the audio codec prefetching data from the old locations 1574 // while the video codec is already reading data from the new 1575 // locations, we'll "pause" the audio source, causing it to 1576 // stop reading input data until a subsequent seek. 1577 1578 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1579 mAudioPlayer->pause(); 1580 1581 modifyFlags(AUDIO_RUNNING, CLEAR); 1582 } 1583 mAudioSource->pause(); 1584 } 1585 } 1586 1587 if (!mVideoBuffer) { 1588 MediaSource::ReadOptions options; 1589 if (mSeeking != NO_SEEK) { 1590 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); 1591 1592 options.setSeekTo( 1593 mSeekTimeUs, 1594 mSeeking == SEEK_VIDEO_ONLY 1595 ? MediaSource::ReadOptions::SEEK_NEXT_SYNC 1596 : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); 1597 } 1598 for (;;) { 1599 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1600 options.clearSeekTo(); 1601 1602 if (err != OK) { 1603 CHECK(mVideoBuffer == NULL); 1604 1605 if (err == INFO_FORMAT_CHANGED) { 1606 LOGV("VideoSource signalled format change."); 1607 1608 notifyVideoSize_l(); 1609 1610 if (mVideoRenderer != NULL) { 1611 mVideoRendererIsPreview = false; 1612 initRenderer_l(); 1613 } 1614 continue; 1615 } 1616 1617 // So video playback is complete, but we may still have 1618 // a seek request pending that needs to be applied 1619 // to the audio track. 1620 if (mSeeking != NO_SEEK) { 1621 LOGV("video stream ended while seeking!"); 1622 } 1623 finishSeekIfNecessary(-1); 1624 1625 if (mAudioPlayer != NULL 1626 && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1627 startAudioPlayer_l(); 1628 } 1629 1630 modifyFlags(VIDEO_AT_EOS, SET); 1631 postStreamDoneEvent_l(err); 1632 return; 1633 } 1634 1635 if (mVideoBuffer->range_length() == 0) { 1636 // Some decoders, notably the PV AVC software decoder 1637 // return spurious empty buffers that we just want to ignore. 1638 1639 mVideoBuffer->release(); 1640 mVideoBuffer = NULL; 1641 continue; 1642 } 1643 1644 break; 1645 } 1646 1647 { 1648 Mutex::Autolock autoLock(mStatsLock); 1649 ++mStats.mNumVideoFramesDecoded; 1650 } 1651 } 1652 1653 int64_t timeUs; 1654 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 1655 1656 mLastVideoTimeUs = timeUs; 1657 1658 if (mSeeking == SEEK_VIDEO_ONLY) { 1659 if (mSeekTimeUs > timeUs) { 1660 LOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us", 1661 mSeekTimeUs, timeUs); 1662 } 1663 } 1664 1665 { 1666 Mutex::Autolock autoLock(mMiscStateLock); 1667 mVideoTimeUs = timeUs; 1668 } 1669 1670 SeekType wasSeeking = mSeeking; 1671 finishSeekIfNecessary(timeUs); 1672 1673 if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1674 status_t err = startAudioPlayer_l(); 1675 if (err != OK) { 1676 LOGE("Startung the audio player failed w/ err %d", err); 1677 return; 1678 } 1679 } 1680 1681 if ((mFlags & TEXTPLAYER_STARTED) && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) { 1682 mTextPlayer->resume(); 1683 modifyFlags(TEXT_RUNNING, SET); 1684 } 1685 1686 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource; 1687 1688 if (mFlags & FIRST_FRAME) { 1689 modifyFlags(FIRST_FRAME, CLEAR); 1690 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs; 1691 } 1692 1693 int64_t realTimeUs, mediaTimeUs; 1694 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL 1695 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 1696 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 1697 } 1698 1699 if (wasSeeking == SEEK_VIDEO_ONLY) { 1700 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; 1701 1702 int64_t latenessUs = nowUs - timeUs; 1703 1704 if (latenessUs > 0) { 1705 LOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6); 1706 } 1707 } 1708 1709 if (wasSeeking == NO_SEEK) { 1710 // Let's display the first frame after seeking right away. 1711 1712 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; 1713 1714 int64_t latenessUs = nowUs - timeUs; 1715 1716 if (latenessUs > 500000ll 1717 && mRTSPController == NULL 1718 && mAudioPlayer != NULL 1719 && mAudioPlayer->getMediaTimeMapping( 1720 &realTimeUs, &mediaTimeUs)) { 1721 LOGI("we're much too late (%.2f secs), video skipping ahead", 1722 latenessUs / 1E6); 1723 1724 mVideoBuffer->release(); 1725 mVideoBuffer = NULL; 1726 1727 mSeeking = SEEK_VIDEO_ONLY; 1728 mSeekTimeUs = mediaTimeUs; 1729 1730 postVideoEvent_l(); 1731 return; 1732 } 1733 1734 if (latenessUs > 40000) { 1735 // We're more than 40ms late. 1736 LOGV("we're late by %lld us (%.2f secs), dropping frame", 1737 latenessUs, latenessUs / 1E6); 1738 mVideoBuffer->release(); 1739 mVideoBuffer = NULL; 1740 1741 { 1742 Mutex::Autolock autoLock(mStatsLock); 1743 ++mStats.mNumVideoFramesDropped; 1744 } 1745 1746 postVideoEvent_l(); 1747 return; 1748 } 1749 1750 if (latenessUs < -10000) { 1751 // We're more than 10ms early. 1752 1753 postVideoEvent_l(10000); 1754 return; 1755 } 1756 } 1757 1758 if (mVideoRendererIsPreview || mVideoRenderer == NULL) { 1759 mVideoRendererIsPreview = false; 1760 1761 initRenderer_l(); 1762 } 1763 1764 if (mVideoRenderer != NULL) { 1765 mVideoRenderer->render(mVideoBuffer); 1766 } 1767 1768 mVideoBuffer->release(); 1769 mVideoBuffer = NULL; 1770 1771 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) { 1772 modifyFlags(SEEK_PREVIEW, CLEAR); 1773 return; 1774 } 1775 1776 postVideoEvent_l(); 1777} 1778 1779void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 1780 if (mVideoEventPending) { 1781 return; 1782 } 1783 1784 mVideoEventPending = true; 1785 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 1786} 1787 1788void AwesomePlayer::postStreamDoneEvent_l(status_t status) { 1789 if (mStreamDoneEventPending) { 1790 return; 1791 } 1792 mStreamDoneEventPending = true; 1793 1794 mStreamDoneStatus = status; 1795 mQueue.postEvent(mStreamDoneEvent); 1796} 1797 1798void AwesomePlayer::postBufferingEvent_l() { 1799 if (mBufferingEventPending) { 1800 return; 1801 } 1802 mBufferingEventPending = true; 1803 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); 1804} 1805 1806void AwesomePlayer::postVideoLagEvent_l() { 1807 if (mVideoLagEventPending) { 1808 return; 1809 } 1810 mVideoLagEventPending = true; 1811 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); 1812} 1813 1814void AwesomePlayer::postCheckAudioStatusEvent_l(int64_t delayUs) { 1815 if (mAudioStatusEventPending) { 1816 return; 1817 } 1818 mAudioStatusEventPending = true; 1819 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs); 1820} 1821 1822void AwesomePlayer::onCheckAudioStatus() { 1823 Mutex::Autolock autoLock(mLock); 1824 if (!mAudioStatusEventPending) { 1825 // Event was dispatched and while we were blocking on the mutex, 1826 // has already been cancelled. 1827 return; 1828 } 1829 1830 mAudioStatusEventPending = false; 1831 1832 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { 1833 mWatchForAudioSeekComplete = false; 1834 1835 if (!mSeekNotificationSent) { 1836 notifyListener_l(MEDIA_SEEK_COMPLETE); 1837 mSeekNotificationSent = true; 1838 } 1839 1840 mSeeking = NO_SEEK; 1841 } 1842 1843 status_t finalStatus; 1844 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) { 1845 mWatchForAudioEOS = false; 1846 modifyFlags(AUDIO_AT_EOS, SET); 1847 modifyFlags(FIRST_FRAME, SET); 1848 postStreamDoneEvent_l(finalStatus); 1849 } 1850} 1851 1852status_t AwesomePlayer::prepare() { 1853 Mutex::Autolock autoLock(mLock); 1854 return prepare_l(); 1855} 1856 1857status_t AwesomePlayer::prepare_l() { 1858 if (mFlags & PREPARED) { 1859 return OK; 1860 } 1861 1862 if (mFlags & PREPARING) { 1863 return UNKNOWN_ERROR; 1864 } 1865 1866 mIsAsyncPrepare = false; 1867 status_t err = prepareAsync_l(); 1868 1869 if (err != OK) { 1870 return err; 1871 } 1872 1873 while (mFlags & PREPARING) { 1874 mPreparedCondition.wait(mLock); 1875 } 1876 1877 return mPrepareResult; 1878} 1879 1880status_t AwesomePlayer::prepareAsync() { 1881 Mutex::Autolock autoLock(mLock); 1882 1883 if (mFlags & PREPARING) { 1884 return UNKNOWN_ERROR; // async prepare already pending 1885 } 1886 1887 mIsAsyncPrepare = true; 1888 return prepareAsync_l(); 1889} 1890 1891status_t AwesomePlayer::prepareAsync_l() { 1892 if (mFlags & PREPARING) { 1893 return UNKNOWN_ERROR; // async prepare already pending 1894 } 1895 1896 if (!mQueueStarted) { 1897 mQueue.start(); 1898 mQueueStarted = true; 1899 } 1900 1901 modifyFlags(PREPARING, SET); 1902 mAsyncPrepareEvent = new AwesomeEvent( 1903 this, &AwesomePlayer::onPrepareAsyncEvent); 1904 1905 mQueue.postEvent(mAsyncPrepareEvent); 1906 1907 return OK; 1908} 1909 1910status_t AwesomePlayer::finishSetDataSource_l() { 1911 sp<DataSource> dataSource; 1912 1913 bool isWidevineStreaming = false; 1914 if (!strncasecmp("widevine://", mUri.string(), 11)) { 1915 isWidevineStreaming = true; 1916 1917 String8 newURI = String8("http://"); 1918 newURI.append(mUri.string() + 11); 1919 1920 mUri = newURI; 1921 } 1922 1923 if (!strncasecmp("http://", mUri.string(), 7) 1924 || !strncasecmp("https://", mUri.string(), 8) 1925 || isWidevineStreaming) { 1926 mConnectingDataSource = HTTPBase::Create( 1927 (mFlags & INCOGNITO) 1928 ? HTTPBase::kFlagIncognito 1929 : 0); 1930 1931 mLock.unlock(); 1932 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); 1933 mLock.lock(); 1934 1935 if (err != OK) { 1936 mConnectingDataSource.clear(); 1937 1938 LOGI("mConnectingDataSource->connect() returned %d", err); 1939 return err; 1940 } 1941 1942 if (!isWidevineStreaming) { 1943 // The widevine extractor does its own caching. 1944 1945#if 0 1946 mCachedSource = new NuCachedSource2( 1947 new ThrottledSource( 1948 mConnectingDataSource, 50 * 1024 /* bytes/sec */)); 1949#else 1950 mCachedSource = new NuCachedSource2(mConnectingDataSource); 1951#endif 1952 1953 dataSource = mCachedSource; 1954 } else { 1955 dataSource = mConnectingDataSource; 1956 } 1957 1958 mConnectingDataSource.clear(); 1959 1960 1961 String8 contentType = dataSource->getMIMEType(); 1962 1963 if (strncasecmp(contentType.string(), "audio/", 6)) { 1964 // We're not doing this for streams that appear to be audio-only 1965 // streams to ensure that even low bandwidth streams start 1966 // playing back fairly instantly. 1967 1968 // We're going to prefill the cache before trying to instantiate 1969 // the extractor below, as the latter is an operation that otherwise 1970 // could block on the datasource for a significant amount of time. 1971 // During that time we'd be unable to abort the preparation phase 1972 // without this prefill. 1973 if (mCachedSource != NULL) { 1974 // We're going to prefill the cache before trying to instantiate 1975 // the extractor below, as the latter is an operation that otherwise 1976 // could block on the datasource for a significant amount of time. 1977 // During that time we'd be unable to abort the preparation phase 1978 // without this prefill. 1979 1980 mLock.unlock(); 1981 1982 for (;;) { 1983 status_t finalStatus; 1984 size_t cachedDataRemaining = 1985 mCachedSource->approxDataRemaining(&finalStatus); 1986 1987 if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes 1988 || (mFlags & PREPARE_CANCELLED)) { 1989 break; 1990 } 1991 1992 usleep(200000); 1993 } 1994 1995 mLock.lock(); 1996 } 1997 1998 if (mFlags & PREPARE_CANCELLED) { 1999 LOGI("Prepare cancelled while waiting for initial cache fill."); 2000 return UNKNOWN_ERROR; 2001 } 2002 } 2003 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) { 2004 if (mLooper == NULL) { 2005 mLooper = new ALooper; 2006 mLooper->setName("rtsp"); 2007 mLooper->start(); 2008 } 2009 mRTSPController = new ARTSPController(mLooper); 2010 mConnectingRTSPController = mRTSPController; 2011 2012 mLock.unlock(); 2013 status_t err = mRTSPController->connect(mUri.string()); 2014 mLock.lock(); 2015 2016 mConnectingRTSPController.clear(); 2017 2018 LOGI("ARTSPController::connect returned %d", err); 2019 2020 if (err != OK) { 2021 mRTSPController.clear(); 2022 return err; 2023 } 2024 2025 sp<MediaExtractor> extractor = mRTSPController.get(); 2026 return setDataSource_l(extractor); 2027 } else { 2028 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); 2029 } 2030 2031 if (dataSource == NULL) { 2032 return UNKNOWN_ERROR; 2033 } 2034 2035 sp<MediaExtractor> extractor; 2036 2037 if (isWidevineStreaming) { 2038 String8 mimeType; 2039 float confidence; 2040 sp<AMessage> dummy; 2041 bool success = SniffDRM(dataSource, &mimeType, &confidence, &dummy); 2042 2043 if (!success 2044 || strcasecmp( 2045 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 2046 return ERROR_UNSUPPORTED; 2047 } 2048 2049 mWVMExtractor = new WVMExtractor(dataSource); 2050 mWVMExtractor->setAdaptiveStreamingMode(true); 2051 extractor = mWVMExtractor; 2052 } else { 2053 extractor = MediaExtractor::Create(dataSource); 2054 2055 if (extractor == NULL) { 2056 return UNKNOWN_ERROR; 2057 } 2058 } 2059 2060 dataSource->getDrmInfo(mDecryptHandle, &mDrmManagerClient); 2061 2062 if (mDecryptHandle != NULL) { 2063 CHECK(mDrmManagerClient); 2064 if (RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 2065 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_DRM_NO_LICENSE); 2066 } 2067 } 2068 2069 status_t err = setDataSource_l(extractor); 2070 2071 if (err != OK) { 2072 mWVMExtractor.clear(); 2073 2074 return err; 2075 } 2076 2077 return OK; 2078} 2079 2080void AwesomePlayer::abortPrepare(status_t err) { 2081 CHECK(err != OK); 2082 2083 if (mIsAsyncPrepare) { 2084 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 2085 } 2086 2087 mPrepareResult = err; 2088 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2089 mAsyncPrepareEvent = NULL; 2090 mPreparedCondition.broadcast(); 2091} 2092 2093// static 2094bool AwesomePlayer::ContinuePreparation(void *cookie) { 2095 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie); 2096 2097 return (me->mFlags & PREPARE_CANCELLED) == 0; 2098} 2099 2100void AwesomePlayer::onPrepareAsyncEvent() { 2101 Mutex::Autolock autoLock(mLock); 2102 2103 if (mFlags & PREPARE_CANCELLED) { 2104 LOGI("prepare was cancelled before doing anything"); 2105 abortPrepare(UNKNOWN_ERROR); 2106 return; 2107 } 2108 2109 if (mUri.size() > 0) { 2110 status_t err = finishSetDataSource_l(); 2111 2112 if (err != OK) { 2113 abortPrepare(err); 2114 return; 2115 } 2116 } 2117 2118 if (mVideoTrack != NULL && mVideoSource == NULL) { 2119 status_t err = initVideoDecoder(); 2120 2121 if (err != OK) { 2122 abortPrepare(err); 2123 return; 2124 } 2125 } 2126 2127 if (mAudioTrack != NULL && mAudioSource == NULL) { 2128 status_t err = initAudioDecoder(); 2129 2130 if (err != OK) { 2131 abortPrepare(err); 2132 return; 2133 } 2134 } 2135 2136 modifyFlags(PREPARING_CONNECTED, SET); 2137 2138 if (isStreamingHTTP() || mRTSPController != NULL) { 2139 postBufferingEvent_l(); 2140 } else { 2141 finishAsyncPrepare_l(); 2142 } 2143} 2144 2145void AwesomePlayer::finishAsyncPrepare_l() { 2146 if (mIsAsyncPrepare) { 2147 if (mVideoSource == NULL) { 2148 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); 2149 } else { 2150 notifyVideoSize_l(); 2151 } 2152 2153 notifyListener_l(MEDIA_PREPARED); 2154 } 2155 2156 mPrepareResult = OK; 2157 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2158 modifyFlags(PREPARED, SET); 2159 mAsyncPrepareEvent = NULL; 2160 mPreparedCondition.broadcast(); 2161} 2162 2163uint32_t AwesomePlayer::flags() const { 2164 return mExtractorFlags; 2165} 2166 2167void AwesomePlayer::postAudioEOS(int64_t delayUs) { 2168 Mutex::Autolock autoLock(mLock); 2169 postCheckAudioStatusEvent_l(delayUs); 2170} 2171 2172void AwesomePlayer::postAudioSeekComplete() { 2173 Mutex::Autolock autoLock(mLock); 2174 postAudioSeekComplete_l(); 2175} 2176 2177void AwesomePlayer::postAudioSeekComplete_l() { 2178 postCheckAudioStatusEvent_l(0 /* delayUs */); 2179} 2180 2181status_t AwesomePlayer::setParameter(int key, const Parcel &request) { 2182 switch (key) { 2183 case KEY_PARAMETER_TIMED_TEXT_TRACK_INDEX: 2184 { 2185 Mutex::Autolock autoLock(mTimedTextLock); 2186 return setTimedTextTrackIndex(request.readInt32()); 2187 } 2188 case KEY_PARAMETER_TIMED_TEXT_ADD_OUT_OF_BAND_SOURCE: 2189 { 2190 Mutex::Autolock autoLock(mTimedTextLock); 2191 if (mTextPlayer == NULL) { 2192 mTextPlayer = new TimedTextPlayer(this, mListener, &mQueue); 2193 } 2194 2195 return mTextPlayer->setParameter(key, request); 2196 } 2197 case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS: 2198 { 2199 return setCacheStatCollectFreq(request); 2200 } 2201 default: 2202 { 2203 return ERROR_UNSUPPORTED; 2204 } 2205 } 2206} 2207 2208status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) { 2209 if (mCachedSource != NULL) { 2210 int32_t freqMs = request.readInt32(); 2211 LOGD("Request to keep cache stats in the past %d ms", 2212 freqMs); 2213 return mCachedSource->setCacheStatCollectFreq(freqMs); 2214 } 2215 return ERROR_UNSUPPORTED; 2216} 2217 2218status_t AwesomePlayer::getParameter(int key, Parcel *reply) { 2219 return OK; 2220} 2221 2222bool AwesomePlayer::isStreamingHTTP() const { 2223 return mCachedSource != NULL || mWVMExtractor != NULL; 2224} 2225 2226status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const { 2227 Mutex::Autolock autoLock(mStatsLock); 2228 2229 FILE *out = fdopen(dup(fd), "w"); 2230 2231 fprintf(out, " AwesomePlayer\n"); 2232 if (mStats.mFd < 0) { 2233 fprintf(out, " URI(%s)", mStats.mURI.string()); 2234 } else { 2235 fprintf(out, " fd(%d)", mStats.mFd); 2236 } 2237 2238 fprintf(out, ", flags(0x%08x)", mStats.mFlags); 2239 2240 if (mStats.mBitrate >= 0) { 2241 fprintf(out, ", bitrate(%lld bps)", mStats.mBitrate); 2242 } 2243 2244 fprintf(out, "\n"); 2245 2246 for (size_t i = 0; i < mStats.mTracks.size(); ++i) { 2247 const TrackStat &stat = mStats.mTracks.itemAt(i); 2248 2249 fprintf(out, " Track %d\n", i + 1); 2250 fprintf(out, " MIME(%s)", stat.mMIME.string()); 2251 2252 if (!stat.mDecoderName.isEmpty()) { 2253 fprintf(out, ", decoder(%s)", stat.mDecoderName.string()); 2254 } 2255 2256 fprintf(out, "\n"); 2257 2258 if ((ssize_t)i == mStats.mVideoTrackIndex) { 2259 fprintf(out, 2260 " videoDimensions(%d x %d), " 2261 "numVideoFramesDecoded(%lld), " 2262 "numVideoFramesDropped(%lld)\n", 2263 mStats.mVideoWidth, 2264 mStats.mVideoHeight, 2265 mStats.mNumVideoFramesDecoded, 2266 mStats.mNumVideoFramesDropped); 2267 } 2268 } 2269 2270 fclose(out); 2271 out = NULL; 2272 2273 return OK; 2274} 2275 2276void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) { 2277 switch (mode) { 2278 case SET: 2279 mFlags |= value; 2280 break; 2281 case CLEAR: 2282 mFlags &= ~value; 2283 break; 2284 case ASSIGN: 2285 mFlags = value; 2286 break; 2287 default: 2288 TRESPASS(); 2289 } 2290 2291 { 2292 Mutex::Autolock autoLock(mStatsLock); 2293 mStats.mFlags = mFlags; 2294 } 2295} 2296 2297} // namespace android 2298