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