AwesomePlayer.cpp revision 15387a6e8e7930ea80f46c98fab54f22981e7f11
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(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str()); 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 bool eos2; 722 int64_t cachedDurationUs; 723 if (getCachedDuration_l(&cachedDurationUs, &eos2) && mDurationUs > 0) { 724 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 725 if (percentage > 100) { 726 percentage = 100; 727 } 728 729 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 730 } else { 731 // We don't know the bitrate/duration of the stream, use absolute size 732 // limits to maintain the cache. 733 734 if ((mFlags & PLAYING) && !eos 735 && (cachedDataRemaining < kLowWaterMarkBytes)) { 736 ALOGI("cache is running low (< %zu) , pausing.", 737 kLowWaterMarkBytes); 738 modifyFlags(CACHE_UNDERRUN, SET); 739 pause_l(); 740 ensureCacheIsFetching_l(); 741 sendCacheStats(); 742 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 743 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { 744 if (mFlags & CACHE_UNDERRUN) { 745 ALOGI("cache has filled up (> %zu), resuming.", 746 kHighWaterMarkBytes); 747 modifyFlags(CACHE_UNDERRUN, CLEAR); 748 play_l(); 749 } else if (mFlags & PREPARING) { 750 ALOGV("cache has filled up (> %zu), prepare is done", 751 kHighWaterMarkBytes); 752 finishAsyncPrepare_l(); 753 } 754 } 755 } 756 } 757 } else if (mWVMExtractor != NULL) { 758 status_t finalStatus; 759 760 int64_t cachedDurationUs 761 = mWVMExtractor->getCachedDurationUs(&finalStatus); 762 763 bool eos = (finalStatus != OK); 764 765 if (eos) { 766 if (finalStatus == ERROR_END_OF_STREAM) { 767 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 768 } 769 if (mFlags & PREPARING) { 770 ALOGV("cache has reached EOS, prepare is done."); 771 finishAsyncPrepare_l(); 772 } 773 } else { 774 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 775 if (percentage > 100) { 776 percentage = 100; 777 } 778 779 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 780 } 781 } 782 783 int64_t cachedDurationUs; 784 bool eos; 785 if (getCachedDuration_l(&cachedDurationUs, &eos)) { 786 ALOGV("cachedDurationUs = %.2f secs, eos=%d", 787 cachedDurationUs / 1E6, eos); 788 789 if ((mFlags & PLAYING) && !eos 790 && (cachedDurationUs < kLowWaterMarkUs)) { 791 modifyFlags(CACHE_UNDERRUN, SET); 792 ALOGI("cache is running low (%.2f secs) , pausing.", 793 cachedDurationUs / 1E6); 794 pause_l(); 795 ensureCacheIsFetching_l(); 796 sendCacheStats(); 797 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 798 } else if (eos || cachedDurationUs > kHighWaterMarkUs) { 799 if (mFlags & CACHE_UNDERRUN) { 800 modifyFlags(CACHE_UNDERRUN, CLEAR); 801 ALOGI("cache has filled up (%.2f secs), resuming.", 802 cachedDurationUs / 1E6); 803 play_l(); 804 } else if (mFlags & PREPARING) { 805 ALOGV("cache has filled up (%.2f secs), prepare is done", 806 cachedDurationUs / 1E6); 807 finishAsyncPrepare_l(); 808 } 809 } 810 } 811 812 if (mFlags & (PLAYING | PREPARING | CACHE_UNDERRUN)) { 813 postBufferingEvent_l(); 814 } 815} 816 817void AwesomePlayer::sendCacheStats() { 818 sp<MediaPlayerBase> listener = mListener.promote(); 819 if (listener != NULL) { 820 int32_t kbps = 0; 821 status_t err = UNKNOWN_ERROR; 822 if (mCachedSource != NULL) { 823 err = mCachedSource->getEstimatedBandwidthKbps(&kbps); 824 } else if (mWVMExtractor != NULL) { 825 err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps); 826 } 827 if (err == OK) { 828 listener->sendEvent( 829 MEDIA_INFO, MEDIA_INFO_NETWORK_BANDWIDTH, kbps); 830 } 831 } 832} 833 834void AwesomePlayer::onStreamDone() { 835 // Posted whenever any stream finishes playing. 836 ATRACE_CALL(); 837 838 Mutex::Autolock autoLock(mLock); 839 if (!mStreamDoneEventPending) { 840 return; 841 } 842 mStreamDoneEventPending = false; 843 844 if (mStreamDoneStatus != ERROR_END_OF_STREAM) { 845 ALOGV("MEDIA_ERROR %d", mStreamDoneStatus); 846 847 notifyListener_l( 848 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus); 849 850 pause_l(true /* at eos */); 851 852 modifyFlags(AT_EOS, SET); 853 return; 854 } 855 856 const bool allDone = 857 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS)) 858 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS)); 859 860 if (!allDone) { 861 return; 862 } 863 864 if ((mFlags & LOOPING) 865 || ((mFlags & AUTO_LOOPING) 866 && (mAudioSink == NULL || mAudioSink->realtime()))) { 867 // Don't AUTO_LOOP if we're being recorded, since that cannot be 868 // turned off and recording would go on indefinitely. 869 870 seekTo_l(0); 871 872 if (mVideoSource != NULL) { 873 postVideoEvent_l(); 874 } 875 } else { 876 ALOGV("MEDIA_PLAYBACK_COMPLETE"); 877 notifyListener_l(MEDIA_PLAYBACK_COMPLETE); 878 879 pause_l(true /* at eos */); 880 881 // If audio hasn't completed MEDIA_SEEK_COMPLETE yet, 882 // notify MEDIA_SEEK_COMPLETE to observer immediately for state persistence. 883 if (mWatchForAudioSeekComplete) { 884 notifyListener_l(MEDIA_SEEK_COMPLETE); 885 mWatchForAudioSeekComplete = false; 886 } 887 888 modifyFlags(AT_EOS, SET); 889 } 890} 891 892status_t AwesomePlayer::play() { 893 ATRACE_CALL(); 894 895 Mutex::Autolock autoLock(mLock); 896 897 modifyFlags(CACHE_UNDERRUN, CLEAR); 898 899 return play_l(); 900} 901 902status_t AwesomePlayer::play_l() { 903 modifyFlags(SEEK_PREVIEW, CLEAR); 904 905 if (mFlags & PLAYING) { 906 return OK; 907 } 908 909 mMediaRenderingStartGeneration = ++mStartGeneration; 910 911 if (!(mFlags & PREPARED)) { 912 status_t err = prepare_l(); 913 914 if (err != OK) { 915 return err; 916 } 917 } 918 919 modifyFlags(PLAYING, SET); 920 modifyFlags(FIRST_FRAME, SET); 921 922 if (mDecryptHandle != NULL) { 923 int64_t position; 924 getPosition(&position); 925 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 926 Playback::START, position / 1000); 927 } 928 929 if (mAudioSource != NULL) { 930 if (mAudioPlayer == NULL) { 931 createAudioPlayer_l(); 932 } 933 934 CHECK(!(mFlags & AUDIO_RUNNING)); 935 936 if (mVideoSource == NULL) { 937 938 // We don't want to post an error notification at this point, 939 // the error returned from MediaPlayer::start() will suffice. 940 941 status_t err = startAudioPlayer_l( 942 false /* sendErrorNotification */); 943 944 if ((err != OK) && mOffloadAudio) { 945 ALOGI("play_l() cannot create offload output, fallback to sw decode"); 946 int64_t curTimeUs; 947 getPosition(&curTimeUs); 948 949 delete mAudioPlayer; 950 mAudioPlayer = NULL; 951 // if the player was started it will take care of stopping the source when destroyed 952 if (!(mFlags & AUDIOPLAYER_STARTED)) { 953 mAudioSource->stop(); 954 } 955 modifyFlags((AUDIO_RUNNING | AUDIOPLAYER_STARTED), CLEAR); 956 mOffloadAudio = false; 957 mAudioSource = mOmxSource; 958 if (mAudioSource != NULL) { 959 err = mAudioSource->start(); 960 961 if (err != OK) { 962 mAudioSource.clear(); 963 } else { 964 mSeekNotificationSent = true; 965 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 966 seekTo_l(curTimeUs); 967 } 968 createAudioPlayer_l(); 969 err = startAudioPlayer_l(false); 970 } 971 } 972 } 973 974 if (err != OK) { 975 delete mAudioPlayer; 976 mAudioPlayer = NULL; 977 978 modifyFlags((PLAYING | FIRST_FRAME), CLEAR); 979 980 if (mDecryptHandle != NULL) { 981 mDrmManagerClient->setPlaybackStatus( 982 mDecryptHandle, Playback::STOP, 0); 983 } 984 985 return err; 986 } 987 } 988 } 989 990 if (mTimeSource == NULL && mAudioPlayer == NULL) { 991 mTimeSource = &mSystemTimeSource; 992 } 993 994 if (mVideoSource != NULL) { 995 // Kick off video playback 996 postVideoEvent_l(); 997 998 if (mAudioSource != NULL && mVideoSource != NULL) { 999 postVideoLagEvent_l(); 1000 } 1001 } 1002 1003 if (mFlags & AT_EOS) { 1004 // Legacy behaviour, if a stream finishes playing and then 1005 // is started again, we play from the start... 1006 seekTo_l(0); 1007 } 1008 1009 uint32_t params = IMediaPlayerService::kBatteryDataCodecStarted 1010 | IMediaPlayerService::kBatteryDataTrackDecoder; 1011 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 1012 params |= IMediaPlayerService::kBatteryDataTrackAudio; 1013 } 1014 if (mVideoSource != NULL) { 1015 params |= IMediaPlayerService::kBatteryDataTrackVideo; 1016 } 1017 addBatteryData(params); 1018 1019 if (isStreamingHTTP()) { 1020 postBufferingEvent_l(); 1021 } 1022 1023 return OK; 1024} 1025 1026void AwesomePlayer::createAudioPlayer_l() 1027{ 1028 uint32_t flags = 0; 1029 int64_t cachedDurationUs; 1030 bool eos; 1031 1032 if (mOffloadAudio) { 1033 flags |= AudioPlayer::USE_OFFLOAD; 1034 } else if (mVideoSource == NULL 1035 && (mDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US || 1036 (getCachedDuration_l(&cachedDurationUs, &eos) && 1037 cachedDurationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US))) { 1038 flags |= AudioPlayer::ALLOW_DEEP_BUFFERING; 1039 } 1040 if (isStreamingHTTP()) { 1041 flags |= AudioPlayer::IS_STREAMING; 1042 } 1043 if (mVideoSource != NULL) { 1044 flags |= AudioPlayer::HAS_VIDEO; 1045 } 1046 1047 mAudioPlayer = new AudioPlayer(mAudioSink, flags, this); 1048 mAudioPlayer->setSource(mAudioSource); 1049 1050 mTimeSource = mAudioPlayer; 1051 1052 // If there was a seek request before we ever started, 1053 // honor the request now. 1054 // Make sure to do this before starting the audio player 1055 // to avoid a race condition. 1056 seekAudioIfNecessary_l(); 1057} 1058 1059void AwesomePlayer::notifyIfMediaStarted_l() { 1060 if (mMediaRenderingStartGeneration == mStartGeneration) { 1061 mMediaRenderingStartGeneration = -1; 1062 notifyListener_l(MEDIA_STARTED); 1063 } 1064} 1065 1066status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) { 1067 CHECK(!(mFlags & AUDIO_RUNNING)); 1068 status_t err = OK; 1069 1070 if (mAudioSource == NULL || mAudioPlayer == NULL) { 1071 return OK; 1072 } 1073 1074 if (mOffloadAudio) { 1075 mQueue.cancelEvent(mAudioTearDownEvent->eventID()); 1076 mAudioTearDownEventPending = false; 1077 } 1078 1079 if (!(mFlags & AUDIOPLAYER_STARTED)) { 1080 bool wasSeeking = mAudioPlayer->isSeeking(); 1081 1082 // We've already started the MediaSource in order to enable 1083 // the prefetcher to read its data. 1084 err = mAudioPlayer->start( 1085 true /* sourceAlreadyStarted */); 1086 1087 if (err != OK) { 1088 if (sendErrorNotification) { 1089 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 1090 } 1091 1092 return err; 1093 } 1094 1095 modifyFlags(AUDIOPLAYER_STARTED, SET); 1096 1097 if (wasSeeking) { 1098 CHECK(!mAudioPlayer->isSeeking()); 1099 1100 // We will have finished the seek while starting the audio player. 1101 postAudioSeekComplete(); 1102 } else { 1103 notifyIfMediaStarted_l(); 1104 } 1105 } else { 1106 err = mAudioPlayer->resume(); 1107 } 1108 1109 if (err == OK) { 1110 modifyFlags(AUDIO_RUNNING, SET); 1111 1112 mWatchForAudioEOS = true; 1113 } 1114 1115 return err; 1116} 1117 1118void AwesomePlayer::notifyVideoSize_l() { 1119 ATRACE_CALL(); 1120 sp<MetaData> meta = mVideoSource->getFormat(); 1121 1122 int32_t cropLeft, cropTop, cropRight, cropBottom; 1123 if (!meta->findRect( 1124 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) { 1125 int32_t width, height; 1126 CHECK(meta->findInt32(kKeyWidth, &width)); 1127 CHECK(meta->findInt32(kKeyHeight, &height)); 1128 1129 cropLeft = cropTop = 0; 1130 cropRight = width - 1; 1131 cropBottom = height - 1; 1132 1133 ALOGV("got dimensions only %d x %d", width, height); 1134 } else { 1135 ALOGV("got crop rect %d, %d, %d, %d", 1136 cropLeft, cropTop, cropRight, cropBottom); 1137 } 1138 1139 int32_t displayWidth; 1140 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) { 1141 ALOGV("Display width changed (%d=>%d)", mDisplayWidth, displayWidth); 1142 mDisplayWidth = displayWidth; 1143 } 1144 int32_t displayHeight; 1145 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) { 1146 ALOGV("Display height changed (%d=>%d)", mDisplayHeight, displayHeight); 1147 mDisplayHeight = displayHeight; 1148 } 1149 1150 int32_t usableWidth = cropRight - cropLeft + 1; 1151 int32_t usableHeight = cropBottom - cropTop + 1; 1152 if (mDisplayWidth != 0) { 1153 usableWidth = mDisplayWidth; 1154 } 1155 if (mDisplayHeight != 0) { 1156 usableHeight = mDisplayHeight; 1157 } 1158 1159 { 1160 Mutex::Autolock autoLock(mStatsLock); 1161 mStats.mVideoWidth = usableWidth; 1162 mStats.mVideoHeight = usableHeight; 1163 } 1164 1165 int32_t rotationDegrees; 1166 if (!mVideoTrack->getFormat()->findInt32( 1167 kKeyRotation, &rotationDegrees)) { 1168 rotationDegrees = 0; 1169 } 1170 1171 if (rotationDegrees == 90 || rotationDegrees == 270) { 1172 notifyListener_l( 1173 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth); 1174 } else { 1175 notifyListener_l( 1176 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight); 1177 } 1178} 1179 1180void AwesomePlayer::initRenderer_l() { 1181 ATRACE_CALL(); 1182 1183 if (mNativeWindow == NULL) { 1184 return; 1185 } 1186 1187 sp<MetaData> meta = mVideoSource->getFormat(); 1188 1189 int32_t format; 1190 const char *component; 1191 int32_t decodedWidth, decodedHeight; 1192 CHECK(meta->findInt32(kKeyColorFormat, &format)); 1193 CHECK(meta->findCString(kKeyDecoderComponent, &component)); 1194 CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); 1195 CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); 1196 1197 int32_t rotationDegrees; 1198 if (!mVideoTrack->getFormat()->findInt32( 1199 kKeyRotation, &rotationDegrees)) { 1200 rotationDegrees = 0; 1201 } 1202 1203 mVideoRenderer.clear(); 1204 1205 // Must ensure that mVideoRenderer's destructor is actually executed 1206 // before creating a new one. 1207 IPCThreadState::self()->flushCommands(); 1208 1209 // Even if set scaling mode fails, we will continue anyway 1210 setVideoScalingMode_l(mVideoScalingMode); 1211 if (USE_SURFACE_ALLOC 1212 && !strncmp(component, "OMX.", 4) 1213 && strncmp(component, "OMX.google.", 11)) { 1214 // Hardware decoders avoid the CPU color conversion by decoding 1215 // directly to ANativeBuffers, so we must use a renderer that 1216 // just pushes those buffers to the ANativeWindow. 1217 mVideoRenderer = 1218 new AwesomeNativeWindowRenderer(mNativeWindow, rotationDegrees); 1219 } else { 1220 // Other decoders are instantiated locally and as a consequence 1221 // allocate their buffers in local address space. This renderer 1222 // then performs a color conversion and copy to get the data 1223 // into the ANativeBuffer. 1224 mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta); 1225 } 1226} 1227 1228status_t AwesomePlayer::pause() { 1229 ATRACE_CALL(); 1230 1231 Mutex::Autolock autoLock(mLock); 1232 1233 modifyFlags(CACHE_UNDERRUN, CLEAR); 1234 1235 return pause_l(); 1236} 1237 1238status_t AwesomePlayer::pause_l(bool at_eos) { 1239 if (!(mFlags & PLAYING)) { 1240 if (mAudioTearDown && mAudioTearDownWasPlaying) { 1241 ALOGV("pause_l() during teardown and finishSetDataSource_l() mFlags %x" , mFlags); 1242 mAudioTearDownWasPlaying = false; 1243 notifyListener_l(MEDIA_PAUSED); 1244 mMediaRenderingStartGeneration = ++mStartGeneration; 1245 } 1246 return OK; 1247 } 1248 1249 notifyListener_l(MEDIA_PAUSED); 1250 mMediaRenderingStartGeneration = ++mStartGeneration; 1251 1252 cancelPlayerEvents(true /* keepNotifications */); 1253 1254 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1255 // If we played the audio stream to completion we 1256 // want to make sure that all samples remaining in the audio 1257 // track's queue are played out. 1258 mAudioPlayer->pause(at_eos /* playPendingSamples */); 1259 // send us a reminder to tear down the AudioPlayer if paused for too long. 1260 if (mOffloadAudio) { 1261 postAudioTearDownEvent(kOffloadPauseMaxUs); 1262 } 1263 modifyFlags(AUDIO_RUNNING, CLEAR); 1264 } 1265 1266 if (mFlags & TEXTPLAYER_INITIALIZED) { 1267 mTextDriver->pause(); 1268 modifyFlags(TEXT_RUNNING, CLEAR); 1269 } 1270 1271 modifyFlags(PLAYING, CLEAR); 1272 1273 if (mDecryptHandle != NULL) { 1274 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1275 Playback::PAUSE, 0); 1276 } 1277 1278 uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; 1279 if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { 1280 params |= IMediaPlayerService::kBatteryDataTrackAudio; 1281 } 1282 if (mVideoSource != NULL) { 1283 params |= IMediaPlayerService::kBatteryDataTrackVideo; 1284 } 1285 1286 addBatteryData(params); 1287 1288 return OK; 1289} 1290 1291bool AwesomePlayer::isPlaying() const { 1292 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN); 1293} 1294 1295status_t AwesomePlayer::setSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) { 1296 Mutex::Autolock autoLock(mLock); 1297 1298 status_t err; 1299 if (bufferProducer != NULL) { 1300 err = setNativeWindow_l(new Surface(bufferProducer)); 1301 } else { 1302 err = setNativeWindow_l(NULL); 1303 } 1304 1305 return err; 1306} 1307 1308void AwesomePlayer::shutdownVideoDecoder_l() { 1309 if (mVideoBuffer) { 1310 mVideoBuffer->release(); 1311 mVideoBuffer = NULL; 1312 } 1313 1314 mVideoSource->stop(); 1315 1316 // The following hack is necessary to ensure that the OMX 1317 // component is completely released by the time we may try 1318 // to instantiate it again. 1319 wp<MediaSource> tmp = mVideoSource; 1320 mVideoSource.clear(); 1321 while (tmp.promote() != NULL) { 1322 usleep(1000); 1323 } 1324 IPCThreadState::self()->flushCommands(); 1325 ALOGV("video decoder shutdown completed"); 1326} 1327 1328status_t AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) { 1329 mNativeWindow = native; 1330 1331 if (mVideoSource == NULL) { 1332 return OK; 1333 } 1334 1335 ALOGV("attempting to reconfigure to use new surface"); 1336 1337 bool wasPlaying = (mFlags & PLAYING) != 0; 1338 1339 pause_l(); 1340 mVideoRenderer.clear(); 1341 1342 shutdownVideoDecoder_l(); 1343 1344 status_t err = initVideoDecoder(); 1345 1346 if (err != OK) { 1347 ALOGE("failed to reinstantiate video decoder after surface change."); 1348 return err; 1349 } 1350 1351 if (mLastVideoTimeUs >= 0) { 1352 mSeeking = SEEK; 1353 mSeekTimeUs = mLastVideoTimeUs; 1354 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1355 } 1356 1357 if (wasPlaying) { 1358 play_l(); 1359 } 1360 1361 return OK; 1362} 1363 1364void AwesomePlayer::setAudioSink( 1365 const sp<MediaPlayerBase::AudioSink> &audioSink) { 1366 Mutex::Autolock autoLock(mLock); 1367 1368 mAudioSink = audioSink; 1369} 1370 1371status_t AwesomePlayer::setLooping(bool shouldLoop) { 1372 Mutex::Autolock autoLock(mLock); 1373 1374 modifyFlags(LOOPING, CLEAR); 1375 1376 if (shouldLoop) { 1377 modifyFlags(LOOPING, SET); 1378 } 1379 1380 return OK; 1381} 1382 1383status_t AwesomePlayer::getDuration(int64_t *durationUs) { 1384 Mutex::Autolock autoLock(mMiscStateLock); 1385 1386 if (mDurationUs < 0) { 1387 return UNKNOWN_ERROR; 1388 } 1389 1390 *durationUs = mDurationUs; 1391 1392 return OK; 1393} 1394 1395status_t AwesomePlayer::getPosition(int64_t *positionUs) { 1396 if (mSeeking != NO_SEEK) { 1397 *positionUs = mSeekTimeUs; 1398 } else if (mVideoSource != NULL 1399 && (mAudioPlayer == NULL || !(mFlags & VIDEO_AT_EOS))) { 1400 Mutex::Autolock autoLock(mMiscStateLock); 1401 *positionUs = mVideoTimeUs; 1402 } else if (mAudioPlayer != NULL) { 1403 *positionUs = mAudioPlayer->getMediaTimeUs(); 1404 } else { 1405 *positionUs = 0; 1406 } 1407 return OK; 1408} 1409 1410status_t AwesomePlayer::seekTo(int64_t timeUs) { 1411 ATRACE_CALL(); 1412 1413 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 1414 Mutex::Autolock autoLock(mLock); 1415 return seekTo_l(timeUs); 1416 } 1417 1418 return OK; 1419} 1420 1421status_t AwesomePlayer::seekTo_l(int64_t timeUs) { 1422 if (mFlags & CACHE_UNDERRUN) { 1423 modifyFlags(CACHE_UNDERRUN, CLEAR); 1424 play_l(); 1425 } 1426 1427 if ((mFlags & PLAYING) && mVideoSource != NULL && (mFlags & VIDEO_AT_EOS)) { 1428 // Video playback completed before, there's no pending 1429 // video event right now. In order for this new seek 1430 // to be honored, we need to post one. 1431 1432 postVideoEvent_l(); 1433 } 1434 1435 mSeeking = SEEK; 1436 mSeekNotificationSent = false; 1437 mSeekTimeUs = timeUs; 1438 modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); 1439 1440 if (mFlags & PLAYING) { 1441 notifyListener_l(MEDIA_PAUSED); 1442 mMediaRenderingStartGeneration = ++mStartGeneration; 1443 } 1444 1445 seekAudioIfNecessary_l(); 1446 1447 if (mFlags & TEXTPLAYER_INITIALIZED) { 1448 mTextDriver->seekToAsync(mSeekTimeUs); 1449 } 1450 1451 if (!(mFlags & PLAYING)) { 1452 ALOGV("seeking while paused, sending SEEK_COMPLETE notification" 1453 " immediately."); 1454 1455 notifyListener_l(MEDIA_SEEK_COMPLETE); 1456 mSeekNotificationSent = true; 1457 1458 if ((mFlags & PREPARED) && mVideoSource != NULL) { 1459 modifyFlags(SEEK_PREVIEW, SET); 1460 postVideoEvent_l(); 1461 } 1462 } 1463 1464 return OK; 1465} 1466 1467void AwesomePlayer::seekAudioIfNecessary_l() { 1468 if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) { 1469 mAudioPlayer->seekTo(mSeekTimeUs); 1470 1471 mWatchForAudioSeekComplete = true; 1472 mWatchForAudioEOS = true; 1473 1474 if (mDecryptHandle != NULL) { 1475 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1476 Playback::PAUSE, 0); 1477 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1478 Playback::START, mSeekTimeUs / 1000); 1479 } 1480 } 1481} 1482 1483void AwesomePlayer::setAudioSource(sp<MediaSource> source) { 1484 CHECK(source != NULL); 1485 1486 mAudioTrack = source; 1487} 1488 1489void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& source) { 1490 CHECK(source != NULL); 1491 1492 if (mTextDriver == NULL) { 1493 mTextDriver = new TimedTextDriver(mListener, mHTTPService); 1494 } 1495 1496 mTextDriver->addInBandTextSource(trackIndex, source); 1497} 1498 1499status_t AwesomePlayer::initAudioDecoder() { 1500 ATRACE_CALL(); 1501 1502 sp<MetaData> meta = mAudioTrack->getFormat(); 1503 1504 const char *mime; 1505 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1506 // Check whether there is a hardware codec for this stream 1507 // This doesn't guarantee that the hardware has a free stream 1508 // but it avoids us attempting to open (and re-open) an offload 1509 // stream to hardware that doesn't have the necessary codec 1510 audio_stream_type_t streamType = AUDIO_STREAM_MUSIC; 1511 if (mAudioSink != NULL) { 1512 streamType = mAudioSink->getAudioStreamType(); 1513 } 1514 1515 mOffloadAudio = canOffloadStream(meta, (mVideoSource != NULL), 1516 isStreamingHTTP(), streamType); 1517 1518 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { 1519 ALOGV("createAudioPlayer: bypass OMX (raw)"); 1520 mAudioSource = mAudioTrack; 1521 } else { 1522 // If offloading we still create a OMX decoder as a fall-back 1523 // but we don't start it 1524 mOmxSource = OMXCodec::Create( 1525 mClient.interface(), mAudioTrack->getFormat(), 1526 false, // createEncoder 1527 mAudioTrack); 1528 1529 if (mOffloadAudio) { 1530 ALOGV("createAudioPlayer: bypass OMX (offload)"); 1531 mAudioSource = mAudioTrack; 1532 } else { 1533 mAudioSource = mOmxSource; 1534 } 1535 } 1536 1537 if (mAudioSource != NULL) { 1538 int64_t durationUs; 1539 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1540 Mutex::Autolock autoLock(mMiscStateLock); 1541 if (mDurationUs < 0 || durationUs > mDurationUs) { 1542 mDurationUs = durationUs; 1543 } 1544 } 1545 1546 status_t err = mAudioSource->start(); 1547 1548 if (err != OK) { 1549 mAudioSource.clear(); 1550 mOmxSource.clear(); 1551 return err; 1552 } 1553 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) { 1554 // For legacy reasons we're simply going to ignore the absence 1555 // of an audio decoder for QCELP instead of aborting playback 1556 // altogether. 1557 return OK; 1558 } 1559 1560 if (mAudioSource != NULL) { 1561 Mutex::Autolock autoLock(mStatsLock); 1562 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mAudioTrackIndex); 1563 const char *component; 1564 if (!mAudioSource->getFormat() 1565 ->findCString(kKeyDecoderComponent, &component)) { 1566 component = "none"; 1567 } 1568 1569 stat->mDecoderName = component; 1570 } 1571 1572 return mAudioSource != NULL ? OK : UNKNOWN_ERROR; 1573} 1574 1575void AwesomePlayer::setVideoSource(sp<MediaSource> source) { 1576 CHECK(source != NULL); 1577 1578 mVideoTrack = source; 1579} 1580 1581status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { 1582 ATRACE_CALL(); 1583 1584 // Either the application or the DRM system can independently say 1585 // that there must be a hardware-protected path to an external video sink. 1586 // For now we always require a hardware-protected path to external video sink 1587 // if content is DRMed, but eventually this could be optional per DRM agent. 1588 // When the application wants protection, then 1589 // (USE_SURFACE_ALLOC && (mSurface != 0) && 1590 // (mSurface->getFlags() & ISurfaceComposer::eProtectedByApp)) 1591 // will be true, but that part is already handled by SurfaceFlinger. 1592 1593#ifdef DEBUG_HDCP 1594 // For debugging, we allow a system property to control the protected usage. 1595 // In case of uninitialized or unexpected property, we default to "DRM only". 1596 bool setProtectionBit = false; 1597 char value[PROPERTY_VALUE_MAX]; 1598 if (property_get("persist.sys.hdcp_checking", value, NULL)) { 1599 if (!strcmp(value, "never")) { 1600 // nop 1601 } else if (!strcmp(value, "always")) { 1602 setProtectionBit = true; 1603 } else if (!strcmp(value, "drm-only")) { 1604 if (mDecryptHandle != NULL) { 1605 setProtectionBit = true; 1606 } 1607 // property value is empty, or unexpected value 1608 } else { 1609 if (mDecryptHandle != NULL) { 1610 setProtectionBit = true; 1611 } 1612 } 1613 // can' read property value 1614 } else { 1615 if (mDecryptHandle != NULL) { 1616 setProtectionBit = true; 1617 } 1618 } 1619 // note that usage bit is already cleared, so no need to clear it in the "else" case 1620 if (setProtectionBit) { 1621 flags |= OMXCodec::kEnableGrallocUsageProtected; 1622 } 1623#else 1624 if (mDecryptHandle != NULL) { 1625 flags |= OMXCodec::kEnableGrallocUsageProtected; 1626 } 1627#endif 1628 ALOGV("initVideoDecoder flags=0x%x", flags); 1629 mVideoSource = OMXCodec::Create( 1630 mClient.interface(), mVideoTrack->getFormat(), 1631 false, // createEncoder 1632 mVideoTrack, 1633 NULL, flags, USE_SURFACE_ALLOC ? mNativeWindow : NULL); 1634 1635 if (mVideoSource != NULL) { 1636 int64_t durationUs; 1637 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1638 Mutex::Autolock autoLock(mMiscStateLock); 1639 if (mDurationUs < 0 || durationUs > mDurationUs) { 1640 mDurationUs = durationUs; 1641 } 1642 } 1643 1644 status_t err = mVideoSource->start(); 1645 1646 if (err != OK) { 1647 ALOGE("failed to start video source"); 1648 mVideoSource.clear(); 1649 return err; 1650 } 1651 } 1652 1653 if (mVideoSource != NULL) { 1654 const char *componentName; 1655 CHECK(mVideoSource->getFormat() 1656 ->findCString(kKeyDecoderComponent, &componentName)); 1657 1658 { 1659 Mutex::Autolock autoLock(mStatsLock); 1660 TrackStat *stat = &mStats.mTracks.editItemAt(mStats.mVideoTrackIndex); 1661 1662 stat->mDecoderName = componentName; 1663 } 1664 1665 static const char *kPrefix = "OMX.Nvidia."; 1666 static const char *kSuffix = ".decode"; 1667 static const size_t kSuffixLength = strlen(kSuffix); 1668 1669 size_t componentNameLength = strlen(componentName); 1670 1671 if (!strncmp(componentName, kPrefix, strlen(kPrefix)) 1672 && componentNameLength >= kSuffixLength 1673 && !strcmp(&componentName[ 1674 componentNameLength - kSuffixLength], kSuffix)) { 1675 modifyFlags(SLOW_DECODER_HACK, SET); 1676 } 1677 } 1678 1679 return mVideoSource != NULL ? OK : UNKNOWN_ERROR; 1680} 1681 1682void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { 1683 ATRACE_CALL(); 1684 1685 if (mSeeking == SEEK_VIDEO_ONLY) { 1686 mSeeking = NO_SEEK; 1687 return; 1688 } 1689 1690 if (mSeeking == NO_SEEK || (mFlags & SEEK_PREVIEW)) { 1691 return; 1692 } 1693 1694 // If we paused, then seeked, then resumed, it is possible that we have 1695 // signaled SEEK_COMPLETE at a copmletely different media time than where 1696 // we are now resuming. Signal new position to media time provider. 1697 // Cannot signal another SEEK_COMPLETE, as existing clients may not expect 1698 // multiple SEEK_COMPLETE responses to a single seek() request. 1699 if (mSeekNotificationSent && abs(mSeekTimeUs - videoTimeUs) > 10000) { 1700 // notify if we are resuming more than 10ms away from desired seek time 1701 notifyListener_l(MEDIA_SKIPPED); 1702 } 1703 1704 if (mAudioPlayer != NULL) { 1705 ALOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6); 1706 1707 // If we don't have a video time, seek audio to the originally 1708 // requested seek time instead. 1709 1710 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs); 1711 mWatchForAudioSeekComplete = true; 1712 mWatchForAudioEOS = true; 1713 } else if (!mSeekNotificationSent) { 1714 // If we're playing video only, report seek complete now, 1715 // otherwise audio player will notify us later. 1716 notifyListener_l(MEDIA_SEEK_COMPLETE); 1717 mSeekNotificationSent = true; 1718 } 1719 1720 modifyFlags(FIRST_FRAME, SET); 1721 mSeeking = NO_SEEK; 1722 1723 if (mDecryptHandle != NULL) { 1724 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1725 Playback::PAUSE, 0); 1726 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1727 Playback::START, videoTimeUs / 1000); 1728 } 1729} 1730 1731void AwesomePlayer::onVideoEvent() { 1732 ATRACE_CALL(); 1733 Mutex::Autolock autoLock(mLock); 1734 if (!mVideoEventPending) { 1735 // The event has been cancelled in reset_l() but had already 1736 // been scheduled for execution at that time. 1737 return; 1738 } 1739 mVideoEventPending = false; 1740 1741 if (mSeeking != NO_SEEK) { 1742 if (mVideoBuffer) { 1743 mVideoBuffer->release(); 1744 mVideoBuffer = NULL; 1745 } 1746 1747 if (mSeeking == SEEK && isStreamingHTTP() && mAudioSource != NULL 1748 && !(mFlags & SEEK_PREVIEW)) { 1749 // We're going to seek the video source first, followed by 1750 // the audio source. 1751 // In order to avoid jumps in the DataSource offset caused by 1752 // the audio codec prefetching data from the old locations 1753 // while the video codec is already reading data from the new 1754 // locations, we'll "pause" the audio source, causing it to 1755 // stop reading input data until a subsequent seek. 1756 1757 if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) { 1758 mAudioPlayer->pause(); 1759 1760 modifyFlags(AUDIO_RUNNING, CLEAR); 1761 } 1762 mAudioSource->pause(); 1763 } 1764 } 1765 1766 if (!mVideoBuffer) { 1767 MediaSource::ReadOptions options; 1768 if (mSeeking != NO_SEEK) { 1769 ALOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); 1770 1771 options.setSeekTo( 1772 mSeekTimeUs, 1773 mSeeking == SEEK_VIDEO_ONLY 1774 ? MediaSource::ReadOptions::SEEK_NEXT_SYNC 1775 : MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); 1776 } 1777 for (;;) { 1778 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1779 options.clearSeekTo(); 1780 1781 if (err != OK) { 1782 CHECK(mVideoBuffer == NULL); 1783 1784 if (err == INFO_FORMAT_CHANGED) { 1785 ALOGV("VideoSource signalled format change."); 1786 1787 notifyVideoSize_l(); 1788 1789 if (mVideoRenderer != NULL) { 1790 mVideoRendererIsPreview = false; 1791 initRenderer_l(); 1792 } 1793 continue; 1794 } 1795 1796 // So video playback is complete, but we may still have 1797 // a seek request pending that needs to be applied 1798 // to the audio track. 1799 if (mSeeking != NO_SEEK) { 1800 ALOGV("video stream ended while seeking!"); 1801 } 1802 finishSeekIfNecessary(-1); 1803 1804 if (mAudioPlayer != NULL 1805 && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1806 startAudioPlayer_l(); 1807 } 1808 1809 modifyFlags(VIDEO_AT_EOS, SET); 1810 postStreamDoneEvent_l(err); 1811 return; 1812 } 1813 1814 if (mVideoBuffer->range_length() == 0) { 1815 // Some decoders, notably the PV AVC software decoder 1816 // return spurious empty buffers that we just want to ignore. 1817 1818 mVideoBuffer->release(); 1819 mVideoBuffer = NULL; 1820 continue; 1821 } 1822 1823 break; 1824 } 1825 1826 { 1827 Mutex::Autolock autoLock(mStatsLock); 1828 ++mStats.mNumVideoFramesDecoded; 1829 } 1830 } 1831 1832 int64_t timeUs; 1833 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 1834 1835 mLastVideoTimeUs = timeUs; 1836 1837 if (mSeeking == SEEK_VIDEO_ONLY) { 1838 if (mSeekTimeUs > timeUs) { 1839 ALOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us", 1840 mSeekTimeUs, timeUs); 1841 } 1842 } 1843 1844 { 1845 Mutex::Autolock autoLock(mMiscStateLock); 1846 mVideoTimeUs = timeUs; 1847 } 1848 1849 SeekType wasSeeking = mSeeking; 1850 finishSeekIfNecessary(timeUs); 1851 1852 if (mAudioPlayer != NULL && !(mFlags & (AUDIO_RUNNING | SEEK_PREVIEW))) { 1853 status_t err = startAudioPlayer_l(); 1854 if (err != OK) { 1855 ALOGE("Starting the audio player failed w/ err %d", err); 1856 return; 1857 } 1858 } 1859 1860 if ((mFlags & TEXTPLAYER_INITIALIZED) 1861 && !(mFlags & (TEXT_RUNNING | SEEK_PREVIEW))) { 1862 mTextDriver->start(); 1863 modifyFlags(TEXT_RUNNING, SET); 1864 } 1865 1866 TimeSource *ts = 1867 ((mFlags & AUDIO_AT_EOS) || !(mFlags & AUDIOPLAYER_STARTED)) 1868 ? &mSystemTimeSource : mTimeSource; 1869 1870 if (mFlags & FIRST_FRAME) { 1871 modifyFlags(FIRST_FRAME, CLEAR); 1872 mSinceLastDropped = 0; 1873 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs; 1874 } 1875 1876 int64_t realTimeUs, mediaTimeUs; 1877 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL 1878 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 1879 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 1880 } 1881 1882 if (wasSeeking == SEEK_VIDEO_ONLY) { 1883 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; 1884 1885 int64_t latenessUs = nowUs - timeUs; 1886 1887 ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); 1888 1889 if (latenessUs > 0) { 1890 ALOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6); 1891 } 1892 } 1893 1894 if (wasSeeking == NO_SEEK) { 1895 // Let's display the first frame after seeking right away. 1896 1897 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; 1898 1899 int64_t latenessUs = nowUs - timeUs; 1900 1901 ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); 1902 1903 if (latenessUs > 500000ll 1904 && mAudioPlayer != NULL 1905 && mAudioPlayer->getMediaTimeMapping( 1906 &realTimeUs, &mediaTimeUs)) { 1907 if (mWVMExtractor == NULL) { 1908 ALOGI("we're much too late (%.2f secs), video skipping ahead", 1909 latenessUs / 1E6); 1910 1911 mVideoBuffer->release(); 1912 mVideoBuffer = NULL; 1913 1914 mSeeking = SEEK_VIDEO_ONLY; 1915 mSeekTimeUs = mediaTimeUs; 1916 1917 postVideoEvent_l(); 1918 return; 1919 } else { 1920 // The widevine extractor doesn't deal well with seeking 1921 // audio and video independently. We'll just have to wait 1922 // until the decoder catches up, which won't be long at all. 1923 ALOGI("we're very late (%.2f secs)", latenessUs / 1E6); 1924 } 1925 } 1926 1927 if (latenessUs > 40000) { 1928 // We're more than 40ms late. 1929 ALOGV("we're late by %lld us (%.2f secs)", 1930 latenessUs, latenessUs / 1E6); 1931 1932 if (!(mFlags & SLOW_DECODER_HACK) 1933 || mSinceLastDropped > FRAME_DROP_FREQ) 1934 { 1935 ALOGV("we're late by %lld us (%.2f secs) dropping " 1936 "one after %d frames", 1937 latenessUs, latenessUs / 1E6, mSinceLastDropped); 1938 1939 mSinceLastDropped = 0; 1940 mVideoBuffer->release(); 1941 mVideoBuffer = NULL; 1942 1943 { 1944 Mutex::Autolock autoLock(mStatsLock); 1945 ++mStats.mNumVideoFramesDropped; 1946 } 1947 1948 postVideoEvent_l(0); 1949 return; 1950 } 1951 } 1952 1953 if (latenessUs < -10000) { 1954 // We're more than 10ms early. 1955 postVideoEvent_l(10000); 1956 return; 1957 } 1958 } 1959 1960 if ((mNativeWindow != NULL) 1961 && (mVideoRendererIsPreview || mVideoRenderer == NULL)) { 1962 mVideoRendererIsPreview = false; 1963 1964 initRenderer_l(); 1965 } 1966 1967 if (mVideoRenderer != NULL) { 1968 mSinceLastDropped++; 1969 mVideoRenderer->render(mVideoBuffer); 1970 if (!mVideoRenderingStarted) { 1971 mVideoRenderingStarted = true; 1972 notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START); 1973 } 1974 1975 if (mFlags & PLAYING) { 1976 notifyIfMediaStarted_l(); 1977 } 1978 } 1979 1980 mVideoBuffer->release(); 1981 mVideoBuffer = NULL; 1982 1983 if (wasSeeking != NO_SEEK && (mFlags & SEEK_PREVIEW)) { 1984 modifyFlags(SEEK_PREVIEW, CLEAR); 1985 return; 1986 } 1987 1988 /* get next frame time */ 1989 if (wasSeeking == NO_SEEK) { 1990 MediaSource::ReadOptions options; 1991 for (;;) { 1992 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1993 if (err != OK) { 1994 // deal with any errors next time 1995 CHECK(mVideoBuffer == NULL); 1996 postVideoEvent_l(0); 1997 return; 1998 } 1999 2000 if (mVideoBuffer->range_length() != 0) { 2001 break; 2002 } 2003 2004 // Some decoders, notably the PV AVC software decoder 2005 // return spurious empty buffers that we just want to ignore. 2006 2007 mVideoBuffer->release(); 2008 mVideoBuffer = NULL; 2009 } 2010 2011 { 2012 Mutex::Autolock autoLock(mStatsLock); 2013 ++mStats.mNumVideoFramesDecoded; 2014 } 2015 2016 int64_t nextTimeUs; 2017 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &nextTimeUs)); 2018 int64_t delayUs = nextTimeUs - ts->getRealTimeUs() + mTimeSourceDeltaUs; 2019 postVideoEvent_l(delayUs > 10000 ? 10000 : delayUs < 0 ? 0 : delayUs); 2020 return; 2021 } 2022 2023 postVideoEvent_l(); 2024} 2025 2026void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 2027 ATRACE_CALL(); 2028 2029 if (mVideoEventPending) { 2030 return; 2031 } 2032 2033 mVideoEventPending = true; 2034 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 2035} 2036 2037void AwesomePlayer::postStreamDoneEvent_l(status_t status) { 2038 if (mStreamDoneEventPending) { 2039 return; 2040 } 2041 mStreamDoneEventPending = true; 2042 2043 mStreamDoneStatus = status; 2044 mQueue.postEvent(mStreamDoneEvent); 2045} 2046 2047void AwesomePlayer::postBufferingEvent_l() { 2048 if (mBufferingEventPending) { 2049 return; 2050 } 2051 mBufferingEventPending = true; 2052 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); 2053} 2054 2055void AwesomePlayer::postVideoLagEvent_l() { 2056 if (mVideoLagEventPending) { 2057 return; 2058 } 2059 mVideoLagEventPending = true; 2060 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); 2061} 2062 2063void AwesomePlayer::postCheckAudioStatusEvent(int64_t delayUs) { 2064 Mutex::Autolock autoLock(mAudioLock); 2065 if (mAudioStatusEventPending) { 2066 return; 2067 } 2068 mAudioStatusEventPending = true; 2069 // Do not honor delay when looping in order to limit audio gap 2070 if (mFlags & (LOOPING | AUTO_LOOPING)) { 2071 delayUs = 0; 2072 } 2073 mQueue.postEventWithDelay(mCheckAudioStatusEvent, delayUs); 2074} 2075 2076void AwesomePlayer::postAudioTearDownEvent(int64_t delayUs) { 2077 Mutex::Autolock autoLock(mAudioLock); 2078 if (mAudioTearDownEventPending) { 2079 return; 2080 } 2081 mAudioTearDownEventPending = true; 2082 mQueue.postEventWithDelay(mAudioTearDownEvent, delayUs); 2083} 2084 2085void AwesomePlayer::onCheckAudioStatus() { 2086 { 2087 Mutex::Autolock autoLock(mAudioLock); 2088 if (!mAudioStatusEventPending) { 2089 // Event was dispatched and while we were blocking on the mutex, 2090 // has already been cancelled. 2091 return; 2092 } 2093 2094 mAudioStatusEventPending = false; 2095 } 2096 2097 Mutex::Autolock autoLock(mLock); 2098 2099 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { 2100 mWatchForAudioSeekComplete = false; 2101 2102 if (!mSeekNotificationSent) { 2103 notifyListener_l(MEDIA_SEEK_COMPLETE); 2104 mSeekNotificationSent = true; 2105 } 2106 2107 if (mVideoSource == NULL) { 2108 // For video the mSeeking flag is always reset in finishSeekIfNecessary 2109 mSeeking = NO_SEEK; 2110 } 2111 2112 notifyIfMediaStarted_l(); 2113 } 2114 2115 status_t finalStatus; 2116 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) { 2117 mWatchForAudioEOS = false; 2118 modifyFlags(AUDIO_AT_EOS, SET); 2119 modifyFlags(FIRST_FRAME, SET); 2120 postStreamDoneEvent_l(finalStatus); 2121 } 2122} 2123 2124status_t AwesomePlayer::prepare() { 2125 ATRACE_CALL(); 2126 Mutex::Autolock autoLock(mLock); 2127 return prepare_l(); 2128} 2129 2130status_t AwesomePlayer::prepare_l() { 2131 if (mFlags & PREPARED) { 2132 return OK; 2133 } 2134 2135 if (mFlags & PREPARING) { 2136 return UNKNOWN_ERROR; 2137 } 2138 2139 mIsAsyncPrepare = false; 2140 status_t err = prepareAsync_l(); 2141 2142 if (err != OK) { 2143 return err; 2144 } 2145 2146 while (mFlags & PREPARING) { 2147 mPreparedCondition.wait(mLock); 2148 } 2149 2150 return mPrepareResult; 2151} 2152 2153status_t AwesomePlayer::prepareAsync() { 2154 ATRACE_CALL(); 2155 Mutex::Autolock autoLock(mLock); 2156 2157 if (mFlags & PREPARING) { 2158 return UNKNOWN_ERROR; // async prepare already pending 2159 } 2160 2161 mIsAsyncPrepare = true; 2162 return prepareAsync_l(); 2163} 2164 2165status_t AwesomePlayer::prepareAsync_l() { 2166 if (mFlags & PREPARING) { 2167 return UNKNOWN_ERROR; // async prepare already pending 2168 } 2169 2170 if (!mQueueStarted) { 2171 mQueue.start(); 2172 mQueueStarted = true; 2173 } 2174 2175 modifyFlags(PREPARING, SET); 2176 mAsyncPrepareEvent = new AwesomeEvent( 2177 this, &AwesomePlayer::onPrepareAsyncEvent); 2178 2179 mQueue.postEvent(mAsyncPrepareEvent); 2180 2181 return OK; 2182} 2183 2184status_t AwesomePlayer::finishSetDataSource_l() { 2185 ATRACE_CALL(); 2186 sp<DataSource> dataSource; 2187 2188 bool isWidevineStreaming = false; 2189 if (!strncasecmp("widevine://", mUri.string(), 11)) { 2190 isWidevineStreaming = true; 2191 2192 String8 newURI = String8("http://"); 2193 newURI.append(mUri.string() + 11); 2194 2195 mUri = newURI; 2196 } 2197 2198 AString sniffedMIME; 2199 2200 if (!strncasecmp("http://", mUri.string(), 7) 2201 || !strncasecmp("https://", mUri.string(), 8) 2202 || isWidevineStreaming) { 2203 if (mHTTPService == NULL) { 2204 ALOGE("Attempt to play media from http URI without HTTP service."); 2205 return UNKNOWN_ERROR; 2206 } 2207 2208 sp<IMediaHTTPConnection> conn = mHTTPService->makeHTTPConnection(); 2209 mConnectingDataSource = new MediaHTTP(conn); 2210 2211 String8 cacheConfig; 2212 bool disconnectAtHighwatermark; 2213 NuCachedSource2::RemoveCacheSpecificHeaders( 2214 &mUriHeaders, &cacheConfig, &disconnectAtHighwatermark); 2215 2216 mLock.unlock(); 2217 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); 2218 // force connection at this point, to avoid a race condition between getMIMEType and the 2219 // caching datasource constructed below, which could result in multiple requests to the 2220 // server, and/or failed connections. 2221 String8 contentType = mConnectingDataSource->getMIMEType(); 2222 mLock.lock(); 2223 2224 if (err != OK) { 2225 mConnectingDataSource.clear(); 2226 2227 ALOGI("mConnectingDataSource->connect() returned %d", err); 2228 return err; 2229 } 2230 2231 if (!isWidevineStreaming) { 2232 // The widevine extractor does its own caching. 2233 2234#if 0 2235 mCachedSource = new NuCachedSource2( 2236 new ThrottledSource( 2237 mConnectingDataSource, 50 * 1024 /* bytes/sec */)); 2238#else 2239 mCachedSource = new NuCachedSource2( 2240 mConnectingDataSource, 2241 cacheConfig.isEmpty() ? NULL : cacheConfig.string(), 2242 disconnectAtHighwatermark); 2243#endif 2244 2245 dataSource = mCachedSource; 2246 } else { 2247 dataSource = mConnectingDataSource; 2248 } 2249 2250 mConnectingDataSource.clear(); 2251 2252 if (strncasecmp(contentType.string(), "audio/", 6)) { 2253 // We're not doing this for streams that appear to be audio-only 2254 // streams to ensure that even low bandwidth streams start 2255 // playing back fairly instantly. 2256 2257 // We're going to prefill the cache before trying to instantiate 2258 // the extractor below, as the latter is an operation that otherwise 2259 // could block on the datasource for a significant amount of time. 2260 // During that time we'd be unable to abort the preparation phase 2261 // without this prefill. 2262 if (mCachedSource != NULL) { 2263 // We're going to prefill the cache before trying to instantiate 2264 // the extractor below, as the latter is an operation that otherwise 2265 // could block on the datasource for a significant amount of time. 2266 // During that time we'd be unable to abort the preparation phase 2267 // without this prefill. 2268 2269 mLock.unlock(); 2270 2271 // Initially make sure we have at least 192 KB for the sniff 2272 // to complete without blocking. 2273 static const size_t kMinBytesForSniffing = 192 * 1024; 2274 2275 off64_t metaDataSize = -1ll; 2276 for (;;) { 2277 status_t finalStatus; 2278 size_t cachedDataRemaining = 2279 mCachedSource->approxDataRemaining(&finalStatus); 2280 2281 if (finalStatus != OK 2282 || (metaDataSize >= 0 2283 && cachedDataRemaining >= metaDataSize) 2284 || (mFlags & PREPARE_CANCELLED)) { 2285 break; 2286 } 2287 2288 ALOGV("now cached %d bytes of data", cachedDataRemaining); 2289 2290 if (metaDataSize < 0 2291 && cachedDataRemaining >= kMinBytesForSniffing) { 2292 String8 tmp; 2293 float confidence; 2294 sp<AMessage> meta; 2295 if (!dataSource->sniff(&tmp, &confidence, &meta)) { 2296 mLock.lock(); 2297 return UNKNOWN_ERROR; 2298 } 2299 2300 // We successfully identified the file's extractor to 2301 // be, remember this mime type so we don't have to 2302 // sniff it again when we call MediaExtractor::Create() 2303 // below. 2304 sniffedMIME = tmp.string(); 2305 2306 if (meta == NULL 2307 || !meta->findInt64("meta-data-size", 2308 reinterpret_cast<int64_t*>(&metaDataSize))) { 2309 metaDataSize = kHighWaterMarkBytes; 2310 } 2311 2312 CHECK_GE(metaDataSize, 0ll); 2313 ALOGV("metaDataSize = %lld bytes", metaDataSize); 2314 } 2315 2316 usleep(200000); 2317 } 2318 2319 mLock.lock(); 2320 } 2321 2322 if (mFlags & PREPARE_CANCELLED) { 2323 ALOGI("Prepare cancelled while waiting for initial cache fill."); 2324 return UNKNOWN_ERROR; 2325 } 2326 } 2327 } else { 2328 dataSource = DataSource::CreateFromURI( 2329 mHTTPService, mUri.string(), &mUriHeaders); 2330 } 2331 2332 if (dataSource == NULL) { 2333 return UNKNOWN_ERROR; 2334 } 2335 2336 sp<MediaExtractor> extractor; 2337 2338 if (isWidevineStreaming) { 2339 String8 mimeType; 2340 float confidence; 2341 sp<AMessage> dummy; 2342 bool success; 2343 2344 // SniffWVM is potentially blocking since it may require network access. 2345 // Do not call it with mLock held. 2346 mLock.unlock(); 2347 success = SniffWVM(dataSource, &mimeType, &confidence, &dummy); 2348 mLock.lock(); 2349 2350 if (!success 2351 || strcasecmp( 2352 mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) { 2353 return ERROR_UNSUPPORTED; 2354 } 2355 2356 mWVMExtractor = new WVMExtractor(dataSource); 2357 mWVMExtractor->setAdaptiveStreamingMode(true); 2358 if (mUIDValid) 2359 mWVMExtractor->setUID(mUID); 2360 extractor = mWVMExtractor; 2361 } else { 2362 extractor = MediaExtractor::Create( 2363 dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str()); 2364 2365 if (extractor == NULL) { 2366 return UNKNOWN_ERROR; 2367 } 2368 } 2369 2370 if (extractor->getDrmFlag()) { 2371 checkDrmStatus(dataSource); 2372 } 2373 2374 status_t err = setDataSource_l(extractor); 2375 2376 if (err != OK) { 2377 mWVMExtractor.clear(); 2378 2379 return err; 2380 } 2381 2382 return OK; 2383} 2384 2385void AwesomePlayer::abortPrepare(status_t err) { 2386 CHECK(err != OK); 2387 2388 if (mIsAsyncPrepare) { 2389 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 2390 } 2391 2392 mPrepareResult = err; 2393 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2394 mAsyncPrepareEvent = NULL; 2395 mPreparedCondition.broadcast(); 2396 mAudioTearDown = false; 2397} 2398 2399// static 2400bool AwesomePlayer::ContinuePreparation(void *cookie) { 2401 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie); 2402 2403 return (me->mFlags & PREPARE_CANCELLED) == 0; 2404} 2405 2406void AwesomePlayer::onPrepareAsyncEvent() { 2407 Mutex::Autolock autoLock(mLock); 2408 beginPrepareAsync_l(); 2409} 2410 2411void AwesomePlayer::beginPrepareAsync_l() { 2412 if (mFlags & PREPARE_CANCELLED) { 2413 ALOGI("prepare was cancelled before doing anything"); 2414 abortPrepare(UNKNOWN_ERROR); 2415 return; 2416 } 2417 2418 if (mUri.size() > 0) { 2419 status_t err = finishSetDataSource_l(); 2420 2421 if (err != OK) { 2422 abortPrepare(err); 2423 return; 2424 } 2425 } 2426 2427 if (mVideoTrack != NULL && mVideoSource == NULL) { 2428 status_t err = initVideoDecoder(); 2429 2430 if (err != OK) { 2431 abortPrepare(err); 2432 return; 2433 } 2434 } 2435 2436 if (mAudioTrack != NULL && mAudioSource == NULL) { 2437 status_t err = initAudioDecoder(); 2438 2439 if (err != OK) { 2440 abortPrepare(err); 2441 return; 2442 } 2443 } 2444 2445 modifyFlags(PREPARING_CONNECTED, SET); 2446 2447 if (isStreamingHTTP()) { 2448 postBufferingEvent_l(); 2449 } else { 2450 finishAsyncPrepare_l(); 2451 } 2452} 2453 2454void AwesomePlayer::finishAsyncPrepare_l() { 2455 if (mIsAsyncPrepare) { 2456 if (mVideoSource == NULL) { 2457 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); 2458 } else { 2459 notifyVideoSize_l(); 2460 } 2461 2462 notifyListener_l(MEDIA_PREPARED); 2463 } 2464 2465 mPrepareResult = OK; 2466 modifyFlags((PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED), CLEAR); 2467 modifyFlags(PREPARED, SET); 2468 mAsyncPrepareEvent = NULL; 2469 mPreparedCondition.broadcast(); 2470 2471 if (mAudioTearDown) { 2472 if (mPrepareResult == OK) { 2473 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 2474 seekTo_l(mAudioTearDownPosition); 2475 } 2476 2477 if (mAudioTearDownWasPlaying) { 2478 modifyFlags(CACHE_UNDERRUN, CLEAR); 2479 play_l(); 2480 } 2481 } 2482 mAudioTearDown = false; 2483 } 2484} 2485 2486uint32_t AwesomePlayer::flags() const { 2487 return mExtractorFlags; 2488} 2489 2490void AwesomePlayer::postAudioEOS(int64_t delayUs) { 2491 postCheckAudioStatusEvent(delayUs); 2492} 2493 2494void AwesomePlayer::postAudioSeekComplete() { 2495 postCheckAudioStatusEvent(0); 2496} 2497 2498void AwesomePlayer::postAudioTearDown() { 2499 postAudioTearDownEvent(0); 2500} 2501 2502status_t AwesomePlayer::setParameter(int key, const Parcel &request) { 2503 switch (key) { 2504 case KEY_PARAMETER_CACHE_STAT_COLLECT_FREQ_MS: 2505 { 2506 return setCacheStatCollectFreq(request); 2507 } 2508 case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE: 2509 { 2510 if (mAudioPlayer != NULL) { 2511 return mAudioPlayer->setPlaybackRatePermille(request.readInt32()); 2512 } else { 2513 return NO_INIT; 2514 } 2515 } 2516 default: 2517 { 2518 return ERROR_UNSUPPORTED; 2519 } 2520 } 2521} 2522 2523status_t AwesomePlayer::setCacheStatCollectFreq(const Parcel &request) { 2524 if (mCachedSource != NULL) { 2525 int32_t freqMs = request.readInt32(); 2526 ALOGD("Request to keep cache stats in the past %d ms", 2527 freqMs); 2528 return mCachedSource->setCacheStatCollectFreq(freqMs); 2529 } 2530 return ERROR_UNSUPPORTED; 2531} 2532 2533status_t AwesomePlayer::getParameter(int key, Parcel *reply) { 2534 switch (key) { 2535 case KEY_PARAMETER_AUDIO_CHANNEL_COUNT: 2536 { 2537 int32_t channelCount; 2538 if (mAudioTrack == 0 || 2539 !mAudioTrack->getFormat()->findInt32(kKeyChannelCount, &channelCount)) { 2540 channelCount = 0; 2541 } 2542 reply->writeInt32(channelCount); 2543 } 2544 return OK; 2545 default: 2546 { 2547 return ERROR_UNSUPPORTED; 2548 } 2549 } 2550} 2551 2552status_t AwesomePlayer::getTrackInfo(Parcel *reply) const { 2553 Mutex::Autolock autoLock(mLock); 2554 size_t trackCount = mExtractor->countTracks(); 2555 if (mTextDriver != NULL) { 2556 trackCount += mTextDriver->countExternalTracks(); 2557 } 2558 2559 reply->writeInt32(trackCount); 2560 for (size_t i = 0; i < mExtractor->countTracks(); ++i) { 2561 sp<MetaData> meta = mExtractor->getTrackMetaData(i); 2562 2563 const char *_mime; 2564 CHECK(meta->findCString(kKeyMIMEType, &_mime)); 2565 2566 String8 mime = String8(_mime); 2567 2568 reply->writeInt32(2); // 2 fields 2569 2570 if (!strncasecmp(mime.string(), "video/", 6)) { 2571 reply->writeInt32(MEDIA_TRACK_TYPE_VIDEO); 2572 } else if (!strncasecmp(mime.string(), "audio/", 6)) { 2573 reply->writeInt32(MEDIA_TRACK_TYPE_AUDIO); 2574 } else if (!strcasecmp(mime.string(), MEDIA_MIMETYPE_TEXT_3GPP)) { 2575 reply->writeInt32(MEDIA_TRACK_TYPE_TIMEDTEXT); 2576 } else { 2577 reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN); 2578 } 2579 2580 const char *lang; 2581 if (!meta->findCString(kKeyMediaLanguage, &lang)) { 2582 lang = "und"; 2583 } 2584 reply->writeString16(String16(lang)); 2585 } 2586 2587 if (mTextDriver != NULL) { 2588 mTextDriver->getExternalTrackInfo(reply); 2589 } 2590 return OK; 2591} 2592 2593status_t AwesomePlayer::selectAudioTrack_l( 2594 const sp<MediaSource>& source, size_t trackIndex) { 2595 2596 ALOGI("selectAudioTrack_l: trackIndex=%zu, mFlags=0x%x", trackIndex, mFlags); 2597 2598 { 2599 Mutex::Autolock autoLock(mStatsLock); 2600 if ((ssize_t)trackIndex == mActiveAudioTrackIndex) { 2601 ALOGI("Track %zu is active. Does nothing.", trackIndex); 2602 return OK; 2603 } 2604 //mStats.mFlags = mFlags; 2605 } 2606 2607 if (mSeeking != NO_SEEK) { 2608 ALOGE("Selecting a track while seeking is not supported"); 2609 return ERROR_UNSUPPORTED; 2610 } 2611 2612 if ((mFlags & PREPARED) == 0) { 2613 ALOGE("Data source has not finished preparation"); 2614 return ERROR_UNSUPPORTED; 2615 } 2616 2617 CHECK(source != NULL); 2618 bool wasPlaying = (mFlags & PLAYING) != 0; 2619 2620 pause_l(); 2621 2622 int64_t curTimeUs; 2623 CHECK_EQ(getPosition(&curTimeUs), (status_t)OK); 2624 2625 if ((mAudioPlayer == NULL || !(mFlags & AUDIOPLAYER_STARTED)) 2626 && mAudioSource != NULL) { 2627 // If we had an audio player, it would have effectively 2628 // taken possession of the audio source and stopped it when 2629 // _it_ is stopped. Otherwise this is still our responsibility. 2630 mAudioSource->stop(); 2631 } 2632 mAudioSource.clear(); 2633 mOmxSource.clear(); 2634 2635 mTimeSource = NULL; 2636 2637 delete mAudioPlayer; 2638 mAudioPlayer = NULL; 2639 2640 modifyFlags(AUDIOPLAYER_STARTED, CLEAR); 2641 2642 setAudioSource(source); 2643 2644 modifyFlags(AUDIO_AT_EOS, CLEAR); 2645 modifyFlags(AT_EOS, CLEAR); 2646 2647 status_t err; 2648 if ((err = initAudioDecoder()) != OK) { 2649 ALOGE("Failed to init audio decoder: 0x%x", err); 2650 return err; 2651 } 2652 2653 mSeekNotificationSent = true; 2654 seekTo_l(curTimeUs); 2655 2656 if (wasPlaying) { 2657 play_l(); 2658 } 2659 2660 mActiveAudioTrackIndex = trackIndex; 2661 2662 return OK; 2663} 2664 2665status_t AwesomePlayer::selectTrack(size_t trackIndex, bool select) { 2666 ATRACE_CALL(); 2667 ALOGV("selectTrack: trackIndex = %d and select=%d", trackIndex, select); 2668 Mutex::Autolock autoLock(mLock); 2669 size_t trackCount = mExtractor->countTracks(); 2670 if (mTextDriver != NULL) { 2671 trackCount += mTextDriver->countExternalTracks(); 2672 } 2673 if (trackIndex >= trackCount) { 2674 ALOGE("Track index (%zu) is out of range [0, %zu)", trackIndex, trackCount); 2675 return ERROR_OUT_OF_RANGE; 2676 } 2677 2678 bool isAudioTrack = false; 2679 if (trackIndex < mExtractor->countTracks()) { 2680 sp<MetaData> meta = mExtractor->getTrackMetaData(trackIndex); 2681 const char *mime; 2682 CHECK(meta->findCString(kKeyMIMEType, &mime)); 2683 isAudioTrack = !strncasecmp(mime, "audio/", 6); 2684 2685 if (!isAudioTrack && strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) != 0) { 2686 ALOGE("Track %zu is not either audio or timed text", trackIndex); 2687 return ERROR_UNSUPPORTED; 2688 } 2689 } 2690 2691 if (isAudioTrack) { 2692 if (!select) { 2693 ALOGE("Deselect an audio track (%zu) is not supported", trackIndex); 2694 return ERROR_UNSUPPORTED; 2695 } 2696 return selectAudioTrack_l(mExtractor->getTrack(trackIndex), trackIndex); 2697 } 2698 2699 // Timed text track handling 2700 if (mTextDriver == NULL) { 2701 return INVALID_OPERATION; 2702 } 2703 2704 status_t err = OK; 2705 if (select) { 2706 err = mTextDriver->selectTrack(trackIndex); 2707 if (err == OK) { 2708 modifyFlags(TEXTPLAYER_INITIALIZED, SET); 2709 if (mFlags & PLAYING && !(mFlags & TEXT_RUNNING)) { 2710 mTextDriver->start(); 2711 modifyFlags(TEXT_RUNNING, SET); 2712 } 2713 } 2714 } else { 2715 err = mTextDriver->unselectTrack(trackIndex); 2716 if (err == OK) { 2717 modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR); 2718 modifyFlags(TEXT_RUNNING, CLEAR); 2719 } 2720 } 2721 return err; 2722} 2723 2724size_t AwesomePlayer::countTracks() const { 2725 return mExtractor->countTracks() + mTextDriver->countExternalTracks(); 2726} 2727 2728status_t AwesomePlayer::setVideoScalingMode(int32_t mode) { 2729 Mutex::Autolock lock(mLock); 2730 return setVideoScalingMode_l(mode); 2731} 2732 2733status_t AwesomePlayer::setVideoScalingMode_l(int32_t mode) { 2734 mVideoScalingMode = mode; 2735 if (mNativeWindow != NULL) { 2736 status_t err = native_window_set_scaling_mode( 2737 mNativeWindow.get(), mVideoScalingMode); 2738 if (err != OK) { 2739 ALOGW("Failed to set scaling mode: %d", err); 2740 } 2741 return err; 2742 } 2743 return OK; 2744} 2745 2746status_t AwesomePlayer::invoke(const Parcel &request, Parcel *reply) { 2747 ATRACE_CALL(); 2748 if (NULL == reply) { 2749 return android::BAD_VALUE; 2750 } 2751 int32_t methodId; 2752 status_t ret = request.readInt32(&methodId); 2753 if (ret != android::OK) { 2754 return ret; 2755 } 2756 switch(methodId) { 2757 case INVOKE_ID_SET_VIDEO_SCALING_MODE: 2758 { 2759 int mode = request.readInt32(); 2760 return setVideoScalingMode(mode); 2761 } 2762 2763 case INVOKE_ID_GET_TRACK_INFO: 2764 { 2765 return getTrackInfo(reply); 2766 } 2767 case INVOKE_ID_ADD_EXTERNAL_SOURCE: 2768 { 2769 Mutex::Autolock autoLock(mLock); 2770 if (mTextDriver == NULL) { 2771 mTextDriver = new TimedTextDriver(mListener, mHTTPService); 2772 } 2773 // String values written in Parcel are UTF-16 values. 2774 String8 uri(request.readString16()); 2775 String8 mimeType(request.readString16()); 2776 size_t nTracks = countTracks(); 2777 return mTextDriver->addOutOfBandTextSource(nTracks, uri, mimeType); 2778 } 2779 case INVOKE_ID_ADD_EXTERNAL_SOURCE_FD: 2780 { 2781 Mutex::Autolock autoLock(mLock); 2782 if (mTextDriver == NULL) { 2783 mTextDriver = new TimedTextDriver(mListener, mHTTPService); 2784 } 2785 int fd = request.readFileDescriptor(); 2786 off64_t offset = request.readInt64(); 2787 off64_t length = request.readInt64(); 2788 String8 mimeType(request.readString16()); 2789 size_t nTracks = countTracks(); 2790 return mTextDriver->addOutOfBandTextSource( 2791 nTracks, fd, offset, length, mimeType); 2792 } 2793 case INVOKE_ID_SELECT_TRACK: 2794 { 2795 int trackIndex = request.readInt32(); 2796 return selectTrack(trackIndex, true /* select */); 2797 } 2798 case INVOKE_ID_UNSELECT_TRACK: 2799 { 2800 int trackIndex = request.readInt32(); 2801 return selectTrack(trackIndex, false /* select */); 2802 } 2803 default: 2804 { 2805 return ERROR_UNSUPPORTED; 2806 } 2807 } 2808 // It will not reach here. 2809 return OK; 2810} 2811 2812bool AwesomePlayer::isStreamingHTTP() const { 2813 return mCachedSource != NULL || mWVMExtractor != NULL; 2814} 2815 2816status_t AwesomePlayer::dump( 2817 int fd, const Vector<String16> & /* args */) const { 2818 Mutex::Autolock autoLock(mStatsLock); 2819 2820 FILE *out = fdopen(dup(fd), "w"); 2821 2822 fprintf(out, " AwesomePlayer\n"); 2823 if (mStats.mFd < 0) { 2824 fprintf(out, " URI(%s)", uriDebugString(mUri, mFlags & INCOGNITO).c_str()); 2825 } else { 2826 fprintf(out, " fd(%d)", mStats.mFd); 2827 } 2828 2829 fprintf(out, ", flags(0x%08x)", mStats.mFlags); 2830 2831 if (mStats.mBitrate >= 0) { 2832 fprintf(out, ", bitrate(%" PRId64 " bps)", mStats.mBitrate); 2833 } 2834 2835 fprintf(out, "\n"); 2836 2837 for (size_t i = 0; i < mStats.mTracks.size(); ++i) { 2838 const TrackStat &stat = mStats.mTracks.itemAt(i); 2839 2840 fprintf(out, " Track %zu\n", i + 1); 2841 fprintf(out, " MIME(%s)", stat.mMIME.string()); 2842 2843 if (!stat.mDecoderName.isEmpty()) { 2844 fprintf(out, ", decoder(%s)", stat.mDecoderName.string()); 2845 } 2846 2847 fprintf(out, "\n"); 2848 2849 if ((ssize_t)i == mStats.mVideoTrackIndex) { 2850 fprintf(out, 2851 " videoDimensions(%d x %d), " 2852 "numVideoFramesDecoded(%" PRId64 "), " 2853 "numVideoFramesDropped(%" PRId64 ")\n", 2854 mStats.mVideoWidth, 2855 mStats.mVideoHeight, 2856 mStats.mNumVideoFramesDecoded, 2857 mStats.mNumVideoFramesDropped); 2858 } 2859 } 2860 2861 fclose(out); 2862 out = NULL; 2863 2864 return OK; 2865} 2866 2867void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) { 2868 switch (mode) { 2869 case SET: 2870 mFlags |= value; 2871 break; 2872 case CLEAR: 2873 if ((value & CACHE_UNDERRUN) && (mFlags & CACHE_UNDERRUN)) { 2874 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 2875 } 2876 mFlags &= ~value; 2877 break; 2878 case ASSIGN: 2879 mFlags = value; 2880 break; 2881 default: 2882 TRESPASS(); 2883 } 2884 2885 { 2886 Mutex::Autolock autoLock(mStatsLock); 2887 mStats.mFlags = mFlags; 2888 } 2889} 2890 2891void AwesomePlayer::onAudioTearDownEvent() { 2892 2893 Mutex::Autolock autoLock(mLock); 2894 if (!mAudioTearDownEventPending) { 2895 return; 2896 } 2897 mAudioTearDownEventPending = false; 2898 2899 ALOGV("onAudioTearDownEvent"); 2900 2901 // stream info is cleared by reset_l() so copy what we need 2902 mAudioTearDownWasPlaying = (mFlags & PLAYING); 2903 KeyedVector<String8, String8> uriHeaders(mUriHeaders); 2904 sp<DataSource> fileSource(mFileSource); 2905 2906 mStatsLock.lock(); 2907 String8 uri(mStats.mURI); 2908 mStatsLock.unlock(); 2909 2910 // get current position so we can start recreated stream from here 2911 getPosition(&mAudioTearDownPosition); 2912 2913 sp<IMediaHTTPService> savedHTTPService = mHTTPService; 2914 2915 // Reset and recreate 2916 reset_l(); 2917 2918 status_t err; 2919 2920 if (fileSource != NULL) { 2921 mFileSource = fileSource; 2922 err = setDataSource_l(fileSource); 2923 } else { 2924 err = setDataSource_l(savedHTTPService, uri, &uriHeaders); 2925 } 2926 2927 mFlags |= PREPARING; 2928 if ( err != OK ) { 2929 // This will force beingPrepareAsync_l() to notify 2930 // a MEDIA_ERROR to the client and abort the prepare 2931 mFlags |= PREPARE_CANCELLED; 2932 } 2933 2934 mAudioTearDown = true; 2935 mIsAsyncPrepare = true; 2936 2937 // Call prepare for the host decoding 2938 beginPrepareAsync_l(); 2939} 2940 2941} // namespace android 2942