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