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