AwesomePlayer.cpp revision 2b1222f8938356669672f35e0e53e176c78c40ef
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//#define LOG_NDEBUG 0 18#define LOG_TAG "AwesomePlayer" 19#include <utils/Log.h> 20 21#include <dlfcn.h> 22 23#include "include/ARTSPController.h" 24#include "include/AwesomePlayer.h" 25#include "include/SoftwareRenderer.h" 26#include "include/NuCachedSource2.h" 27#include "include/ThrottledSource.h" 28#include "include/MPEG2TSExtractor.h" 29 30#include "ARTPSession.h" 31#include "APacketSource.h" 32#include "ASessionDescription.h" 33#include "UDPPusher.h" 34 35#include <binder/IPCThreadState.h> 36#include <media/stagefright/foundation/hexdump.h> 37#include <media/stagefright/foundation/ADebug.h> 38#include <media/stagefright/AudioPlayer.h> 39#include <media/stagefright/DataSource.h> 40#include <media/stagefright/FileSource.h> 41#include <media/stagefright/MediaBuffer.h> 42#include <media/stagefright/MediaDefs.h> 43#include <media/stagefright/MediaExtractor.h> 44#include <media/stagefright/MediaSource.h> 45#include <media/stagefright/MetaData.h> 46#include <media/stagefright/OMXCodec.h> 47 48#include <surfaceflinger/Surface.h> 49 50#include <media/stagefright/foundation/ALooper.h> 51#include <media/stagefright/foundation/AMessage.h> 52#include "include/LiveSession.h" 53 54#define USE_SURFACE_ALLOC 1 55#define FRAME_DROP_FREQ 7 56 57namespace android { 58 59static int64_t kLowWaterMarkUs = 2000000ll; // 2secs 60static int64_t kHighWaterMarkUs = 10000000ll; // 10secs 61static const size_t kLowWaterMarkBytes = 40000; 62static const size_t kHighWaterMarkBytes = 200000; 63 64struct AwesomeEvent : public TimedEventQueue::Event { 65 AwesomeEvent( 66 AwesomePlayer *player, 67 void (AwesomePlayer::*method)()) 68 : mPlayer(player), 69 mMethod(method) { 70 } 71 72protected: 73 virtual ~AwesomeEvent() {} 74 75 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { 76 (mPlayer->*mMethod)(); 77 } 78 79private: 80 AwesomePlayer *mPlayer; 81 void (AwesomePlayer::*mMethod)(); 82 83 AwesomeEvent(const AwesomeEvent &); 84 AwesomeEvent &operator=(const AwesomeEvent &); 85}; 86 87struct AwesomeLocalRenderer : public AwesomeRenderer { 88 AwesomeLocalRenderer( 89 const sp<Surface> &surface, const sp<MetaData> &meta) 90 : mTarget(new SoftwareRenderer(surface, meta)) { 91 } 92 93 virtual void render(MediaBuffer *buffer) { 94 render((const uint8_t *)buffer->data() + buffer->range_offset(), 95 buffer->range_length()); 96 } 97 98 void render(const void *data, size_t size) { 99 mTarget->render(data, size, NULL); 100 } 101 102protected: 103 virtual ~AwesomeLocalRenderer() { 104 delete mTarget; 105 mTarget = NULL; 106 } 107 108private: 109 SoftwareRenderer *mTarget; 110 111 AwesomeLocalRenderer(const AwesomeLocalRenderer &); 112 AwesomeLocalRenderer &operator=(const AwesomeLocalRenderer &);; 113}; 114 115struct AwesomeNativeWindowRenderer : public AwesomeRenderer { 116 AwesomeNativeWindowRenderer( 117 const sp<ANativeWindow> &nativeWindow, 118 int32_t rotationDegrees) 119 : mNativeWindow(nativeWindow) { 120 applyRotation(rotationDegrees); 121 } 122 123 virtual void render(MediaBuffer *buffer) { 124 status_t err = mNativeWindow->queueBuffer( 125 mNativeWindow.get(), buffer->graphicBuffer().get()); 126 if (err != 0) { 127 LOGE("queueBuffer failed with error %s (%d)", strerror(-err), 128 -err); 129 return; 130 } 131 132 sp<MetaData> metaData = buffer->meta_data(); 133 metaData->setInt32(kKeyRendered, 1); 134 } 135 136protected: 137 virtual ~AwesomeNativeWindowRenderer() {} 138 139private: 140 sp<ANativeWindow> mNativeWindow; 141 142 void applyRotation(int32_t rotationDegrees) { 143 uint32_t transform; 144 switch (rotationDegrees) { 145 case 0: transform = 0; break; 146 case 90: transform = HAL_TRANSFORM_ROT_90; break; 147 case 180: transform = HAL_TRANSFORM_ROT_180; break; 148 case 270: transform = HAL_TRANSFORM_ROT_270; break; 149 default: transform = 0; break; 150 } 151 152 if (transform) { 153 CHECK_EQ(0, native_window_set_buffers_transform( 154 mNativeWindow.get(), transform)); 155 } 156 } 157 158 AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &); 159 AwesomeNativeWindowRenderer &operator=( 160 const AwesomeNativeWindowRenderer &); 161}; 162 163//////////////////////////////////////////////////////////////////////////////// 164 165AwesomePlayer::AwesomePlayer() 166 : mQueueStarted(false), 167 mTimeSource(NULL), 168 mVideoRendererIsPreview(false), 169 mAudioPlayer(NULL), 170 mDisplayWidth(0), 171 mDisplayHeight(0), 172 mFlags(0), 173 mExtractorFlags(0), 174 mVideoBuffer(NULL), 175 mDecryptHandle(NULL) { 176 CHECK_EQ(mClient.connect(), (status_t)OK); 177 178 DataSource::RegisterDefaultSniffers(); 179 180 mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); 181 mVideoEventPending = false; 182 mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone); 183 mStreamDoneEventPending = false; 184 mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate); 185 mBufferingEventPending = false; 186 mVideoLagEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoLagUpdate); 187 mVideoEventPending = false; 188 189 mCheckAudioStatusEvent = new AwesomeEvent( 190 this, &AwesomePlayer::onCheckAudioStatus); 191 192 mAudioStatusEventPending = false; 193 194 reset(); 195} 196 197AwesomePlayer::~AwesomePlayer() { 198 if (mQueueStarted) { 199 mQueue.stop(); 200 } 201 202 reset(); 203 204 mClient.disconnect(); 205} 206 207void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) { 208 mQueue.cancelEvent(mVideoEvent->eventID()); 209 mVideoEventPending = false; 210 mQueue.cancelEvent(mStreamDoneEvent->eventID()); 211 mStreamDoneEventPending = false; 212 mQueue.cancelEvent(mCheckAudioStatusEvent->eventID()); 213 mAudioStatusEventPending = false; 214 mQueue.cancelEvent(mVideoLagEvent->eventID()); 215 mVideoLagEventPending = false; 216 217 if (!keepBufferingGoing) { 218 mQueue.cancelEvent(mBufferingEvent->eventID()); 219 mBufferingEventPending = false; 220 } 221} 222 223void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) { 224 Mutex::Autolock autoLock(mLock); 225 mListener = listener; 226} 227 228status_t AwesomePlayer::setDataSource( 229 const char *uri, const KeyedVector<String8, String8> *headers) { 230 Mutex::Autolock autoLock(mLock); 231 return setDataSource_l(uri, headers); 232} 233 234status_t AwesomePlayer::setDataSource_l( 235 const char *uri, const KeyedVector<String8, String8> *headers) { 236 reset_l(); 237 238 mUri = uri; 239 240 if (!strncmp("http://", uri, 7)) { 241 // Hack to support http live. 242 243 size_t len = strlen(uri); 244 if (!strcasecmp(&uri[len - 5], ".m3u8") 245 || strstr(&uri[7], "m3u8") != NULL) { 246 mUri = "httplive://"; 247 mUri.append(&uri[7]); 248 } 249 } 250 251 if (headers) { 252 mUriHeaders = *headers; 253 } 254 255 // The actual work will be done during preparation in the call to 256 // ::finishSetDataSource_l to avoid blocking the calling thread in 257 // setDataSource for any significant time. 258 259 return OK; 260} 261 262status_t AwesomePlayer::setDataSource( 263 int fd, int64_t offset, int64_t length) { 264 Mutex::Autolock autoLock(mLock); 265 266 reset_l(); 267 268 sp<DataSource> dataSource = new FileSource(fd, offset, length); 269 270 status_t err = dataSource->initCheck(); 271 272 if (err != OK) { 273 return err; 274 } 275 276 mFileSource = dataSource; 277 278 return setDataSource_l(dataSource); 279} 280 281status_t AwesomePlayer::setDataSource(const sp<IStreamSource> &source) { 282 return INVALID_OPERATION; 283} 284 285status_t AwesomePlayer::setDataSource_l( 286 const sp<DataSource> &dataSource) { 287 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 288 289 if (extractor == NULL) { 290 return UNKNOWN_ERROR; 291 } 292 293 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient); 294 if (mDecryptHandle != NULL 295 && RightsStatus::RIGHTS_VALID != mDecryptHandle->status) { 296 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE); 297 } 298 299 return setDataSource_l(extractor); 300} 301 302status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { 303 // Attempt to approximate overall stream bitrate by summing all 304 // tracks' individual bitrates, if not all of them advertise bitrate, 305 // we have to fail. 306 307 int64_t totalBitRate = 0; 308 309 for (size_t i = 0; i < extractor->countTracks(); ++i) { 310 sp<MetaData> meta = extractor->getTrackMetaData(i); 311 312 int32_t bitrate; 313 if (!meta->findInt32(kKeyBitRate, &bitrate)) { 314 totalBitRate = -1; 315 break; 316 } 317 318 totalBitRate += bitrate; 319 } 320 321 mBitrate = totalBitRate; 322 323 LOGV("mBitrate = %lld bits/sec", mBitrate); 324 325 bool haveAudio = false; 326 bool haveVideo = false; 327 for (size_t i = 0; i < extractor->countTracks(); ++i) { 328 sp<MetaData> meta = extractor->getTrackMetaData(i); 329 330 const char *mime; 331 CHECK(meta->findCString(kKeyMIMEType, &mime)); 332 333 if (!haveVideo && !strncasecmp(mime, "video/", 6)) { 334 setVideoSource(extractor->getTrack(i)); 335 haveVideo = true; 336 337 // Set the presentation/display size 338 int32_t displayWidth, displayHeight; 339 bool success = meta->findInt32(kKeyDisplayWidth, &displayWidth); 340 if (success) { 341 success = meta->findInt32(kKeyDisplayHeight, &displayHeight); 342 } 343 if (success) { 344 mDisplayWidth = displayWidth; 345 mDisplayHeight = displayHeight; 346 } 347 348 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { 349 setAudioSource(extractor->getTrack(i)); 350 haveAudio = true; 351 352 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { 353 // Only do this for vorbis audio, none of the other audio 354 // formats even support this ringtone specific hack and 355 // retrieving the metadata on some extractors may turn out 356 // to be very expensive. 357 sp<MetaData> fileMeta = extractor->getMetaData(); 358 int32_t loop; 359 if (fileMeta != NULL 360 && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) { 361 mFlags |= AUTO_LOOPING; 362 } 363 } 364 } 365 366 if (haveAudio && haveVideo) { 367 break; 368 } 369 } 370 371 if (!haveAudio && !haveVideo) { 372 return UNKNOWN_ERROR; 373 } 374 375 mExtractorFlags = extractor->flags(); 376 377 return OK; 378} 379 380void AwesomePlayer::reset() { 381 LOGI("reset"); 382 383 Mutex::Autolock autoLock(mLock); 384 reset_l(); 385} 386 387void AwesomePlayer::reset_l() { 388 LOGI("reset_l"); 389 mDisplayWidth = 0; 390 mDisplayHeight = 0; 391 392 if (mDecryptHandle != NULL) { 393 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 394 Playback::STOP, 0); 395 mDrmManagerClient->closeDecryptSession(mDecryptHandle); 396 mDecryptHandle = NULL; 397 mDrmManagerClient = NULL; 398 } 399 400 if (mFlags & PREPARING) { 401 mFlags |= PREPARE_CANCELLED; 402 if (mConnectingDataSource != NULL) { 403 LOGI("interrupting the connection process"); 404 mConnectingDataSource->disconnect(); 405 } 406 407 if (mFlags & PREPARING_CONNECTED) { 408 // We are basically done preparing, we're just buffering 409 // enough data to start playback, we can safely interrupt that. 410 finishAsyncPrepare_l(); 411 } 412 } 413 414 if (mFlags & PREPARING) { 415 LOGI("waiting until preparation is completes."); 416 } 417 418 while (mFlags & PREPARING) { 419 mPreparedCondition.wait(mLock); 420 } 421 422 cancelPlayerEvents(); 423 424 mCachedSource.clear(); 425 mAudioTrack.clear(); 426 mVideoTrack.clear(); 427 428 // Shutdown audio first, so that the respone to the reset request 429 // appears to happen instantaneously as far as the user is concerned 430 // If we did this later, audio would continue playing while we 431 // shutdown the video-related resources and the player appear to 432 // not be as responsive to a reset request. 433 if (mAudioPlayer == NULL && mAudioSource != NULL) { 434 // If we had an audio player, it would have effectively 435 // taken possession of the audio source and stopped it when 436 // _it_ is stopped. Otherwise this is still our responsibility. 437 mAudioSource->stop(); 438 } 439 mAudioSource.clear(); 440 441 LOGI("audio source cleared"); 442 443 mTimeSource = NULL; 444 445 delete mAudioPlayer; 446 mAudioPlayer = NULL; 447 448 mVideoRenderer.clear(); 449 450 if (mVideoBuffer) { 451 mVideoBuffer->release(); 452 mVideoBuffer = NULL; 453 } 454 455 if (mRTSPController != NULL) { 456 mRTSPController->disconnect(); 457 mRTSPController.clear(); 458 } 459 460 if (mLiveSession != NULL) { 461 mLiveSession->disconnect(); 462 mLiveSession.clear(); 463 } 464 465 mRTPPusher.clear(); 466 mRTCPPusher.clear(); 467 mRTPSession.clear(); 468 469 if (mVideoSource != NULL) { 470 mVideoSource->stop(); 471 472 // The following hack is necessary to ensure that the OMX 473 // component is completely released by the time we may try 474 // to instantiate it again. 475 wp<MediaSource> tmp = mVideoSource; 476 mVideoSource.clear(); 477 while (tmp.promote() != NULL) { 478 usleep(1000); 479 } 480 IPCThreadState::self()->flushCommands(); 481 } 482 483 LOGI("video source cleared"); 484 485 mDurationUs = -1; 486 mFlags = 0; 487 mExtractorFlags = 0; 488 mTimeSourceDeltaUs = 0; 489 mVideoTimeUs = 0; 490 491 mSeeking = false; 492 mSeekNotificationSent = false; 493 mSeekTimeUs = 0; 494 495 mUri.setTo(""); 496 mUriHeaders.clear(); 497 498 mFileSource.clear(); 499 500 mBitrate = -1; 501 502 LOGI("reset_l completed"); 503} 504 505void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { 506 if (mListener != NULL) { 507 sp<MediaPlayerBase> listener = mListener.promote(); 508 509 if (listener != NULL) { 510 listener->sendEvent(msg, ext1, ext2); 511 } 512 } 513} 514 515bool AwesomePlayer::getBitrate(int64_t *bitrate) { 516 off64_t size; 517 if (mDurationUs >= 0 && mCachedSource != NULL 518 && mCachedSource->getSize(&size) == OK) { 519 *bitrate = size * 8000000ll / mDurationUs; // in bits/sec 520 return true; 521 } 522 523 if (mBitrate >= 0) { 524 *bitrate = mBitrate; 525 return true; 526 } 527 528 *bitrate = 0; 529 530 return false; 531} 532 533// Returns true iff cached duration is available/applicable. 534bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { 535 int64_t bitrate; 536 537 if (mRTSPController != NULL) { 538 *durationUs = mRTSPController->getQueueDurationUs(eos); 539 return true; 540 } else if (mCachedSource != NULL && getBitrate(&bitrate)) { 541 status_t finalStatus; 542 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 543 *durationUs = cachedDataRemaining * 8000000ll / bitrate; 544 *eos = (finalStatus != OK); 545 return true; 546 } 547 548 return false; 549} 550 551void AwesomePlayer::ensureCacheIsFetching_l() { 552 if (mCachedSource != NULL) { 553 mCachedSource->resumeFetchingIfNecessary(); 554 } 555} 556 557void AwesomePlayer::onVideoLagUpdate() { 558 Mutex::Autolock autoLock(mLock); 559 if (!mVideoLagEventPending) { 560 return; 561 } 562 mVideoLagEventPending = false; 563 564 int64_t audioTimeUs = mAudioPlayer->getMediaTimeUs(); 565 int64_t videoLateByUs = audioTimeUs - mVideoTimeUs; 566 567 if (videoLateByUs > 300000ll) { 568 LOGV("video late by %lld ms.", videoLateByUs / 1000ll); 569 570 notifyListener_l( 571 MEDIA_INFO, 572 MEDIA_INFO_VIDEO_TRACK_LAGGING, 573 videoLateByUs / 1000ll); 574 } 575 576 postVideoLagEvent_l(); 577} 578 579void AwesomePlayer::onBufferingUpdate() { 580 Mutex::Autolock autoLock(mLock); 581 if (!mBufferingEventPending) { 582 return; 583 } 584 mBufferingEventPending = false; 585 586 if (mCachedSource != NULL) { 587 status_t finalStatus; 588 size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); 589 bool eos = (finalStatus != OK); 590 591 if (eos) { 592 if (finalStatus == ERROR_END_OF_STREAM) { 593 notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); 594 } 595 if (mFlags & PREPARING) { 596 LOGV("cache has reached EOS, prepare is done."); 597 finishAsyncPrepare_l(); 598 } 599 } else { 600 int64_t bitrate; 601 if (getBitrate(&bitrate)) { 602 size_t cachedSize = mCachedSource->cachedSize(); 603 int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; 604 605 int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; 606 if (percentage > 100) { 607 percentage = 100; 608 } 609 610 notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); 611 } else { 612 // We don't know the bitrate of the stream, use absolute size 613 // limits to maintain the cache. 614 615 if ((mFlags & PLAYING) && !eos 616 && (cachedDataRemaining < kLowWaterMarkBytes)) { 617 LOGI("cache is running low (< %d) , pausing.", 618 kLowWaterMarkBytes); 619 mFlags |= CACHE_UNDERRUN; 620 pause_l(); 621 ensureCacheIsFetching_l(); 622 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 623 } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { 624 if (mFlags & CACHE_UNDERRUN) { 625 LOGI("cache has filled up (> %d), resuming.", 626 kHighWaterMarkBytes); 627 mFlags &= ~CACHE_UNDERRUN; 628 play_l(); 629 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 630 } else if (mFlags & PREPARING) { 631 LOGV("cache has filled up (> %d), prepare is done", 632 kHighWaterMarkBytes); 633 finishAsyncPrepare_l(); 634 } 635 } 636 } 637 } 638 } 639 640 int64_t cachedDurationUs; 641 bool eos; 642 if (getCachedDuration_l(&cachedDurationUs, &eos)) { 643 LOGV("cachedDurationUs = %.2f secs, eos=%d", 644 cachedDurationUs / 1E6, eos); 645 646 if ((mFlags & PLAYING) && !eos 647 && (cachedDurationUs < kLowWaterMarkUs)) { 648 LOGI("cache is running low (%.2f secs) , pausing.", 649 cachedDurationUs / 1E6); 650 mFlags |= CACHE_UNDERRUN; 651 pause_l(); 652 ensureCacheIsFetching_l(); 653 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); 654 } else if (eos || cachedDurationUs > kHighWaterMarkUs) { 655 if (mFlags & CACHE_UNDERRUN) { 656 LOGI("cache has filled up (%.2f secs), resuming.", 657 cachedDurationUs / 1E6); 658 mFlags &= ~CACHE_UNDERRUN; 659 play_l(); 660 notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); 661 } else if (mFlags & PREPARING) { 662 LOGV("cache has filled up (%.2f secs), prepare is done", 663 cachedDurationUs / 1E6); 664 finishAsyncPrepare_l(); 665 } 666 } 667 } 668 669 postBufferingEvent_l(); 670} 671 672void AwesomePlayer::partial_reset_l() { 673 // Only reset the video renderer and shut down the video decoder. 674 // Then instantiate a new video decoder and resume video playback. 675 676 mVideoRenderer.clear(); 677 678 if (mVideoBuffer) { 679 mVideoBuffer->release(); 680 mVideoBuffer = NULL; 681 } 682 683 { 684 mVideoSource->stop(); 685 686 // The following hack is necessary to ensure that the OMX 687 // component is completely released by the time we may try 688 // to instantiate it again. 689 wp<MediaSource> tmp = mVideoSource; 690 mVideoSource.clear(); 691 while (tmp.promote() != NULL) { 692 usleep(1000); 693 } 694 IPCThreadState::self()->flushCommands(); 695 } 696 697 CHECK_EQ((status_t)OK, 698 initVideoDecoder(OMXCodec::kIgnoreCodecSpecificData)); 699} 700 701void AwesomePlayer::onStreamDone() { 702 // Posted whenever any stream finishes playing. 703 704 Mutex::Autolock autoLock(mLock); 705 if (!mStreamDoneEventPending) { 706 return; 707 } 708 mStreamDoneEventPending = false; 709 710 if (mStreamDoneStatus == INFO_DISCONTINUITY) { 711 // This special status is returned because an http live stream's 712 // video stream switched to a different bandwidth at this point 713 // and future data may have been encoded using different parameters. 714 // This requires us to shutdown the video decoder and reinstantiate 715 // a fresh one. 716 717 LOGV("INFO_DISCONTINUITY"); 718 719 CHECK(mVideoSource != NULL); 720 721 partial_reset_l(); 722 postVideoEvent_l(); 723 return; 724 } else if (mStreamDoneStatus != ERROR_END_OF_STREAM) { 725 LOGV("MEDIA_ERROR %d", mStreamDoneStatus); 726 727 notifyListener_l( 728 MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, mStreamDoneStatus); 729 730 pause_l(true /* at eos */); 731 732 mFlags |= AT_EOS; 733 return; 734 } 735 736 const bool allDone = 737 (mVideoSource == NULL || (mFlags & VIDEO_AT_EOS)) 738 && (mAudioSource == NULL || (mFlags & AUDIO_AT_EOS)); 739 740 if (!allDone) { 741 return; 742 } 743 744 if (mFlags & (LOOPING | AUTO_LOOPING)) { 745 seekTo_l(0); 746 747 if (mVideoSource != NULL) { 748 postVideoEvent_l(); 749 } 750 } else { 751 LOGV("MEDIA_PLAYBACK_COMPLETE"); 752 notifyListener_l(MEDIA_PLAYBACK_COMPLETE); 753 754 pause_l(true /* at eos */); 755 756 mFlags |= AT_EOS; 757 } 758} 759 760status_t AwesomePlayer::play() { 761 Mutex::Autolock autoLock(mLock); 762 763 mFlags &= ~CACHE_UNDERRUN; 764 765 return play_l(); 766} 767 768status_t AwesomePlayer::play_l() { 769 mFlags &= ~SEEK_PREVIEW; 770 771 if (mFlags & PLAYING) { 772 return OK; 773 } 774 775 if (!(mFlags & PREPARED)) { 776 status_t err = prepare_l(); 777 778 if (err != OK) { 779 return err; 780 } 781 } 782 783 mFlags |= PLAYING; 784 mFlags |= FIRST_FRAME; 785 786 bool deferredAudioSeek = false; 787 788 if (mDecryptHandle != NULL) { 789 int64_t position; 790 getPosition(&position); 791 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 792 Playback::START, position / 1000); 793 } 794 795 if (mAudioSource != NULL) { 796 if (mAudioPlayer == NULL) { 797 if (mAudioSink != NULL) { 798 mAudioPlayer = new AudioPlayer(mAudioSink, this); 799 mAudioPlayer->setSource(mAudioSource); 800 801 // We've already started the MediaSource in order to enable 802 // the prefetcher to read its data. 803 status_t err = mAudioPlayer->start( 804 true /* sourceAlreadyStarted */); 805 806 if (err != OK) { 807 delete mAudioPlayer; 808 mAudioPlayer = NULL; 809 810 mFlags &= ~(PLAYING | FIRST_FRAME); 811 812 if (mDecryptHandle != NULL) { 813 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 814 Playback::STOP, 0); 815 } 816 817 return err; 818 } 819 820 mTimeSource = mAudioPlayer; 821 822 deferredAudioSeek = true; 823 824 mWatchForAudioSeekComplete = false; 825 mWatchForAudioEOS = true; 826 } 827 } else { 828 mAudioPlayer->resume(); 829 } 830 } 831 832 if (mTimeSource == NULL && mAudioPlayer == NULL) { 833 mTimeSource = &mSystemTimeSource; 834 } 835 836 if (mVideoSource != NULL) { 837 // Kick off video playback 838 postVideoEvent_l(); 839 840 if (mAudioSource != NULL && mVideoSource != NULL) { 841 postVideoLagEvent_l(); 842 } 843 } 844 845 if (deferredAudioSeek) { 846 // If there was a seek request while we were paused 847 // and we're just starting up again, honor the request now. 848 seekAudioIfNecessary_l(); 849 } 850 851 if (mFlags & AT_EOS) { 852 // Legacy behaviour, if a stream finishes playing and then 853 // is started again, we play from the start... 854 seekTo_l(0); 855 } 856 857 return OK; 858} 859 860void AwesomePlayer::notifyVideoSize_l() { 861 sp<MetaData> meta = mVideoSource->getFormat(); 862 863 int32_t cropLeft, cropTop, cropRight, cropBottom; 864 if (!meta->findRect( 865 kKeyCropRect, &cropLeft, &cropTop, &cropRight, &cropBottom)) { 866 int32_t width, height; 867 CHECK(meta->findInt32(kKeyWidth, &width)); 868 CHECK(meta->findInt32(kKeyHeight, &height)); 869 870 cropLeft = cropTop = 0; 871 cropRight = width - 1; 872 cropBottom = height - 1; 873 874 LOGV("got dimensions only %d x %d", width, height); 875 } else { 876 LOGV("got crop rect %d, %d, %d, %d", 877 cropLeft, cropTop, cropRight, cropBottom); 878 } 879 880 int32_t usableWidth = cropRight - cropLeft + 1; 881 int32_t usableHeight = cropBottom - cropTop + 1; 882 if (mDisplayWidth != 0) { 883 usableWidth = mDisplayWidth; 884 } 885 if (mDisplayHeight != 0) { 886 usableHeight = mDisplayHeight; 887 } 888 889 int32_t rotationDegrees; 890 if (!mVideoTrack->getFormat()->findInt32( 891 kKeyRotation, &rotationDegrees)) { 892 rotationDegrees = 0; 893 } 894 895 if (rotationDegrees == 90 || rotationDegrees == 270) { 896 notifyListener_l( 897 MEDIA_SET_VIDEO_SIZE, usableHeight, usableWidth); 898 } else { 899 notifyListener_l( 900 MEDIA_SET_VIDEO_SIZE, usableWidth, usableHeight); 901 } 902} 903 904void AwesomePlayer::initRenderer_l() { 905 if (mSurface == NULL) { 906 return; 907 } 908 909 sp<MetaData> meta = mVideoSource->getFormat(); 910 911 int32_t format; 912 const char *component; 913 int32_t decodedWidth, decodedHeight; 914 CHECK(meta->findInt32(kKeyColorFormat, &format)); 915 CHECK(meta->findCString(kKeyDecoderComponent, &component)); 916 CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); 917 CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); 918 919 int32_t rotationDegrees; 920 if (!mVideoTrack->getFormat()->findInt32( 921 kKeyRotation, &rotationDegrees)) { 922 rotationDegrees = 0; 923 } 924 925 mVideoRenderer.clear(); 926 927 // Must ensure that mVideoRenderer's destructor is actually executed 928 // before creating a new one. 929 IPCThreadState::self()->flushCommands(); 930 931 if (USE_SURFACE_ALLOC && strncmp(component, "OMX.", 4) == 0) { 932 // Hardware decoders avoid the CPU color conversion by decoding 933 // directly to ANativeBuffers, so we must use a renderer that 934 // just pushes those buffers to the ANativeWindow. 935 mVideoRenderer = 936 new AwesomeNativeWindowRenderer(mSurface, rotationDegrees); 937 } else { 938 // Other decoders are instantiated locally and as a consequence 939 // allocate their buffers in local address space. This renderer 940 // then performs a color conversion and copy to get the data 941 // into the ANativeBuffer. 942 mVideoRenderer = new AwesomeLocalRenderer(mSurface, meta); 943 } 944} 945 946status_t AwesomePlayer::pause() { 947 Mutex::Autolock autoLock(mLock); 948 949 mFlags &= ~CACHE_UNDERRUN; 950 951 return pause_l(); 952} 953 954status_t AwesomePlayer::pause_l(bool at_eos) { 955 if (!(mFlags & PLAYING)) { 956 return OK; 957 } 958 959 cancelPlayerEvents(true /* keepBufferingGoing */); 960 961 if (mAudioPlayer != NULL) { 962 if (at_eos) { 963 // If we played the audio stream to completion we 964 // want to make sure that all samples remaining in the audio 965 // track's queue are played out. 966 mAudioPlayer->pause(true /* playPendingSamples */); 967 } else { 968 mAudioPlayer->pause(); 969 } 970 } 971 972 mFlags &= ~PLAYING; 973 974 if (mDecryptHandle != NULL) { 975 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 976 Playback::PAUSE, 0); 977 } 978 979 return OK; 980} 981 982bool AwesomePlayer::isPlaying() const { 983 return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN); 984} 985 986void AwesomePlayer::setSurface(const sp<Surface> &surface) { 987 Mutex::Autolock autoLock(mLock); 988 989 mSurface = surface; 990} 991 992void AwesomePlayer::setAudioSink( 993 const sp<MediaPlayerBase::AudioSink> &audioSink) { 994 Mutex::Autolock autoLock(mLock); 995 996 mAudioSink = audioSink; 997} 998 999status_t AwesomePlayer::setLooping(bool shouldLoop) { 1000 Mutex::Autolock autoLock(mLock); 1001 1002 mFlags = mFlags & ~LOOPING; 1003 1004 if (shouldLoop) { 1005 mFlags |= LOOPING; 1006 } 1007 1008 return OK; 1009} 1010 1011status_t AwesomePlayer::getDuration(int64_t *durationUs) { 1012 Mutex::Autolock autoLock(mMiscStateLock); 1013 1014 if (mDurationUs < 0) { 1015 return UNKNOWN_ERROR; 1016 } 1017 1018 *durationUs = mDurationUs; 1019 1020 return OK; 1021} 1022 1023status_t AwesomePlayer::getPosition(int64_t *positionUs) { 1024 if (mRTSPController != NULL) { 1025 *positionUs = mRTSPController->getNormalPlayTimeUs(); 1026 } 1027 else if (mSeeking) { 1028 *positionUs = mSeekTimeUs; 1029 } else if (mVideoSource != NULL) { 1030 Mutex::Autolock autoLock(mMiscStateLock); 1031 *positionUs = mVideoTimeUs; 1032 } else if (mAudioPlayer != NULL) { 1033 *positionUs = mAudioPlayer->getMediaTimeUs(); 1034 } else { 1035 *positionUs = 0; 1036 } 1037 1038 return OK; 1039} 1040 1041status_t AwesomePlayer::seekTo(int64_t timeUs) { 1042 if (mExtractorFlags & MediaExtractor::CAN_SEEK) { 1043 Mutex::Autolock autoLock(mLock); 1044 return seekTo_l(timeUs); 1045 } 1046 1047 return OK; 1048} 1049 1050// static 1051void AwesomePlayer::OnRTSPSeekDoneWrapper(void *cookie) { 1052 static_cast<AwesomePlayer *>(cookie)->onRTSPSeekDone(); 1053} 1054 1055void AwesomePlayer::onRTSPSeekDone() { 1056 notifyListener_l(MEDIA_SEEK_COMPLETE); 1057 mSeekNotificationSent = true; 1058} 1059 1060status_t AwesomePlayer::seekTo_l(int64_t timeUs) { 1061 if (mRTSPController != NULL) { 1062 mRTSPController->seekAsync(timeUs, OnRTSPSeekDoneWrapper, this); 1063 return OK; 1064 } 1065 1066 if (mFlags & CACHE_UNDERRUN) { 1067 mFlags &= ~CACHE_UNDERRUN; 1068 play_l(); 1069 } 1070 1071 mSeeking = true; 1072 mSeekNotificationSent = false; 1073 mSeekTimeUs = timeUs; 1074 mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS); 1075 1076 seekAudioIfNecessary_l(); 1077 1078 if (!(mFlags & PLAYING)) { 1079 LOGV("seeking while paused, sending SEEK_COMPLETE notification" 1080 " immediately."); 1081 1082 notifyListener_l(MEDIA_SEEK_COMPLETE); 1083 mSeekNotificationSent = true; 1084 1085 if ((mFlags & PREPARED) && mVideoSource != NULL) { 1086 mFlags |= SEEK_PREVIEW; 1087 postVideoEvent_l(); 1088 } 1089 } 1090 1091 return OK; 1092} 1093 1094void AwesomePlayer::seekAudioIfNecessary_l() { 1095 if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) { 1096 mAudioPlayer->seekTo(mSeekTimeUs); 1097 1098 mWatchForAudioSeekComplete = true; 1099 mWatchForAudioEOS = true; 1100 mSeekNotificationSent = false; 1101 1102 if (mDecryptHandle != NULL) { 1103 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1104 Playback::PAUSE, 0); 1105 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1106 Playback::START, mSeekTimeUs / 1000); 1107 } 1108 } 1109} 1110 1111void AwesomePlayer::setAudioSource(sp<MediaSource> source) { 1112 CHECK(source != NULL); 1113 1114 mAudioTrack = source; 1115} 1116 1117status_t AwesomePlayer::initAudioDecoder() { 1118 sp<MetaData> meta = mAudioTrack->getFormat(); 1119 1120 const char *mime; 1121 CHECK(meta->findCString(kKeyMIMEType, &mime)); 1122 1123 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { 1124 mAudioSource = mAudioTrack; 1125 } else { 1126 mAudioSource = OMXCodec::Create( 1127 mClient.interface(), mAudioTrack->getFormat(), 1128 false, // createEncoder 1129 mAudioTrack); 1130 } 1131 1132 if (mAudioSource != NULL) { 1133 int64_t durationUs; 1134 if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1135 Mutex::Autolock autoLock(mMiscStateLock); 1136 if (mDurationUs < 0 || durationUs > mDurationUs) { 1137 mDurationUs = durationUs; 1138 } 1139 } 1140 1141 status_t err = mAudioSource->start(); 1142 1143 if (err != OK) { 1144 mAudioSource.clear(); 1145 return err; 1146 } 1147 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_QCELP)) { 1148 // For legacy reasons we're simply going to ignore the absence 1149 // of an audio decoder for QCELP instead of aborting playback 1150 // altogether. 1151 return OK; 1152 } 1153 1154 return mAudioSource != NULL ? OK : UNKNOWN_ERROR; 1155} 1156 1157void AwesomePlayer::setVideoSource(sp<MediaSource> source) { 1158 CHECK(source != NULL); 1159 1160 mVideoTrack = source; 1161} 1162 1163status_t AwesomePlayer::initVideoDecoder(uint32_t flags) { 1164 mVideoSource = OMXCodec::Create( 1165 mClient.interface(), mVideoTrack->getFormat(), 1166 false, // createEncoder 1167 mVideoTrack, 1168 NULL, flags, USE_SURFACE_ALLOC ? mSurface : NULL); 1169 1170 if (mVideoSource != NULL) { 1171 int64_t durationUs; 1172 if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { 1173 Mutex::Autolock autoLock(mMiscStateLock); 1174 if (mDurationUs < 0 || durationUs > mDurationUs) { 1175 mDurationUs = durationUs; 1176 } 1177 } 1178 1179 status_t err = mVideoSource->start(); 1180 1181 if (err != OK) { 1182 mVideoSource.clear(); 1183 return err; 1184 } 1185 } 1186 1187 return mVideoSource != NULL ? OK : UNKNOWN_ERROR; 1188} 1189 1190void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { 1191 if (!mSeeking || (mFlags & SEEK_PREVIEW)) { 1192 return; 1193 } 1194 1195 if (mAudioPlayer != NULL) { 1196 LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6); 1197 1198 // If we don't have a video time, seek audio to the originally 1199 // requested seek time instead. 1200 1201 mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs); 1202 mAudioPlayer->resume(); 1203 mWatchForAudioSeekComplete = true; 1204 mWatchForAudioEOS = true; 1205 } else if (!mSeekNotificationSent) { 1206 // If we're playing video only, report seek complete now, 1207 // otherwise audio player will notify us later. 1208 notifyListener_l(MEDIA_SEEK_COMPLETE); 1209 } 1210 1211 mFlags |= FIRST_FRAME; 1212 mSeeking = false; 1213 mSeekNotificationSent = false; 1214 1215 if (mDecryptHandle != NULL) { 1216 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1217 Playback::PAUSE, 0); 1218 mDrmManagerClient->setPlaybackStatus(mDecryptHandle, 1219 Playback::START, videoTimeUs / 1000); 1220 } 1221} 1222 1223void AwesomePlayer::onVideoEvent() { 1224 Mutex::Autolock autoLock(mLock); 1225 if (!mVideoEventPending) { 1226 // The event has been cancelled in reset_l() but had already 1227 // been scheduled for execution at that time. 1228 return; 1229 } 1230 mVideoEventPending = false; 1231 1232 if (mSeeking) { 1233 if (mVideoBuffer) { 1234 mVideoBuffer->release(); 1235 mVideoBuffer = NULL; 1236 } 1237 1238 if (mCachedSource != NULL && mAudioSource != NULL 1239 && !(mFlags & SEEK_PREVIEW)) { 1240 // We're going to seek the video source first, followed by 1241 // the audio source. 1242 // In order to avoid jumps in the DataSource offset caused by 1243 // the audio codec prefetching data from the old locations 1244 // while the video codec is already reading data from the new 1245 // locations, we'll "pause" the audio source, causing it to 1246 // stop reading input data until a subsequent seek. 1247 1248 if (mAudioPlayer != NULL) { 1249 mAudioPlayer->pause(); 1250 } 1251 mAudioSource->pause(); 1252 } 1253 } 1254 1255 if (!mVideoBuffer) { 1256 MediaSource::ReadOptions options; 1257 if (mSeeking) { 1258 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); 1259 1260 options.setSeekTo( 1261 mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); 1262 } 1263 for (;;) { 1264 status_t err = mVideoSource->read(&mVideoBuffer, &options); 1265 options.clearSeekTo(); 1266 1267 if (err != OK) { 1268 CHECK(mVideoBuffer == NULL); 1269 1270 if (err == INFO_FORMAT_CHANGED) { 1271 LOGV("VideoSource signalled format change."); 1272 1273 notifyVideoSize_l(); 1274 1275 if (mVideoRenderer != NULL) { 1276 mVideoRendererIsPreview = false; 1277 initRenderer_l(); 1278 } 1279 continue; 1280 } 1281 1282 // So video playback is complete, but we may still have 1283 // a seek request pending that needs to be applied 1284 // to the audio track. 1285 if (mSeeking) { 1286 LOGV("video stream ended while seeking!"); 1287 } 1288 finishSeekIfNecessary(-1); 1289 1290 mFlags |= VIDEO_AT_EOS; 1291 postStreamDoneEvent_l(err); 1292 return; 1293 } 1294 1295 if (mVideoBuffer->range_length() == 0) { 1296 // Some decoders, notably the PV AVC software decoder 1297 // return spurious empty buffers that we just want to ignore. 1298 1299 mVideoBuffer->release(); 1300 mVideoBuffer = NULL; 1301 continue; 1302 } 1303 1304 break; 1305 } 1306 } 1307 1308 int64_t timeUs; 1309 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 1310 1311 { 1312 Mutex::Autolock autoLock(mMiscStateLock); 1313 mVideoTimeUs = timeUs; 1314 } 1315 1316 bool wasSeeking = mSeeking; 1317 finishSeekIfNecessary(timeUs); 1318 1319 TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource; 1320 1321 if (mFlags & FIRST_FRAME) { 1322 mFlags &= ~FIRST_FRAME; 1323 mSinceLastDropped = 0; 1324 mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs; 1325 } 1326 1327 int64_t realTimeUs, mediaTimeUs; 1328 if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL 1329 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 1330 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 1331 } 1332 1333 if (!wasSeeking && mRTPSession == NULL) { 1334 // Let's display the first frame after seeking right away. 1335 // We'll completely ignore timestamps for gtalk videochat 1336 // and we'll play incoming video as fast as we get it. 1337 1338 int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; 1339 1340 int64_t latenessUs = nowUs - timeUs; 1341 1342 if (latenessUs > 40000) { 1343 // We're more than 40ms late. 1344 LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6); 1345 if ( mSinceLastDropped > FRAME_DROP_FREQ) 1346 { 1347 LOGV("we're late by %lld us (%.2f secs) dropping one after %d frames", latenessUs, latenessUs / 1E6, mSinceLastDropped); 1348 mSinceLastDropped = 0; 1349 mVideoBuffer->release(); 1350 mVideoBuffer = NULL; 1351 1352 postVideoEvent_l(); 1353 return; 1354 } 1355 } 1356 1357 if (latenessUs < -10000) { 1358 // We're more than 10ms early. 1359 1360 postVideoEvent_l(10000); 1361 return; 1362 } 1363 } 1364 1365 if (mVideoRendererIsPreview || mVideoRenderer == NULL) { 1366 mVideoRendererIsPreview = false; 1367 1368 initRenderer_l(); 1369 } 1370 1371 if (mVideoRenderer != NULL) { 1372 mSinceLastDropped++; 1373 mVideoRenderer->render(mVideoBuffer); 1374 } 1375 1376 mVideoBuffer->release(); 1377 mVideoBuffer = NULL; 1378 1379 if (wasSeeking && (mFlags & SEEK_PREVIEW)) { 1380 mFlags &= ~SEEK_PREVIEW; 1381 return; 1382 } 1383 1384 postVideoEvent_l(); 1385} 1386 1387void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 1388 if (mVideoEventPending) { 1389 return; 1390 } 1391 1392 mVideoEventPending = true; 1393 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 1394} 1395 1396void AwesomePlayer::postStreamDoneEvent_l(status_t status) { 1397 if (mStreamDoneEventPending) { 1398 return; 1399 } 1400 mStreamDoneEventPending = true; 1401 1402 mStreamDoneStatus = status; 1403 mQueue.postEvent(mStreamDoneEvent); 1404} 1405 1406void AwesomePlayer::postBufferingEvent_l() { 1407 if (mBufferingEventPending) { 1408 return; 1409 } 1410 mBufferingEventPending = true; 1411 mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); 1412} 1413 1414void AwesomePlayer::postVideoLagEvent_l() { 1415 if (mVideoLagEventPending) { 1416 return; 1417 } 1418 mVideoLagEventPending = true; 1419 mQueue.postEventWithDelay(mVideoLagEvent, 1000000ll); 1420} 1421 1422void AwesomePlayer::postCheckAudioStatusEvent_l() { 1423 if (mAudioStatusEventPending) { 1424 return; 1425 } 1426 mAudioStatusEventPending = true; 1427 mQueue.postEvent(mCheckAudioStatusEvent); 1428} 1429 1430void AwesomePlayer::onCheckAudioStatus() { 1431 Mutex::Autolock autoLock(mLock); 1432 if (!mAudioStatusEventPending) { 1433 // Event was dispatched and while we were blocking on the mutex, 1434 // has already been cancelled. 1435 return; 1436 } 1437 1438 mAudioStatusEventPending = false; 1439 1440 if (mWatchForAudioSeekComplete && !mAudioPlayer->isSeeking()) { 1441 mWatchForAudioSeekComplete = false; 1442 1443 if (!mSeekNotificationSent) { 1444 notifyListener_l(MEDIA_SEEK_COMPLETE); 1445 mSeekNotificationSent = true; 1446 } 1447 1448 mSeeking = false; 1449 } 1450 1451 status_t finalStatus; 1452 if (mWatchForAudioEOS && mAudioPlayer->reachedEOS(&finalStatus)) { 1453 mWatchForAudioEOS = false; 1454 mFlags |= AUDIO_AT_EOS; 1455 mFlags |= FIRST_FRAME; 1456 postStreamDoneEvent_l(finalStatus); 1457 } 1458} 1459 1460status_t AwesomePlayer::prepare() { 1461 Mutex::Autolock autoLock(mLock); 1462 return prepare_l(); 1463} 1464 1465status_t AwesomePlayer::prepare_l() { 1466 if (mFlags & PREPARED) { 1467 return OK; 1468 } 1469 1470 if (mFlags & PREPARING) { 1471 return UNKNOWN_ERROR; 1472 } 1473 1474 mIsAsyncPrepare = false; 1475 status_t err = prepareAsync_l(); 1476 1477 if (err != OK) { 1478 return err; 1479 } 1480 1481 while (mFlags & PREPARING) { 1482 mPreparedCondition.wait(mLock); 1483 } 1484 1485 return mPrepareResult; 1486} 1487 1488status_t AwesomePlayer::prepareAsync() { 1489 Mutex::Autolock autoLock(mLock); 1490 1491 if (mFlags & PREPARING) { 1492 return UNKNOWN_ERROR; // async prepare already pending 1493 } 1494 1495 mIsAsyncPrepare = true; 1496 return prepareAsync_l(); 1497} 1498 1499status_t AwesomePlayer::prepareAsync_l() { 1500 if (mFlags & PREPARING) { 1501 return UNKNOWN_ERROR; // async prepare already pending 1502 } 1503 1504 if (!mQueueStarted) { 1505 mQueue.start(); 1506 mQueueStarted = true; 1507 } 1508 1509 mFlags |= PREPARING; 1510 mAsyncPrepareEvent = new AwesomeEvent( 1511 this, &AwesomePlayer::onPrepareAsyncEvent); 1512 1513 mQueue.postEvent(mAsyncPrepareEvent); 1514 1515 return OK; 1516} 1517 1518status_t AwesomePlayer::finishSetDataSource_l() { 1519 sp<DataSource> dataSource; 1520 1521 if (!strncasecmp("http://", mUri.string(), 7)) { 1522 mConnectingDataSource = new NuHTTPDataSource; 1523 1524 mLock.unlock(); 1525 status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); 1526 mLock.lock(); 1527 1528 if (err != OK) { 1529 mConnectingDataSource.clear(); 1530 1531 LOGI("mConnectingDataSource->connect() returned %d", err); 1532 return err; 1533 } 1534 1535#if 0 1536 mCachedSource = new NuCachedSource2( 1537 new ThrottledSource( 1538 mConnectingDataSource, 50 * 1024 /* bytes/sec */)); 1539#else 1540 mCachedSource = new NuCachedSource2(mConnectingDataSource); 1541#endif 1542 mConnectingDataSource.clear(); 1543 1544 dataSource = mCachedSource; 1545 1546 // We're going to prefill the cache before trying to instantiate 1547 // the extractor below, as the latter is an operation that otherwise 1548 // could block on the datasource for a significant amount of time. 1549 // During that time we'd be unable to abort the preparation phase 1550 // without this prefill. 1551 1552 mLock.unlock(); 1553 1554 for (;;) { 1555 status_t finalStatus; 1556 size_t cachedDataRemaining = 1557 mCachedSource->approxDataRemaining(&finalStatus); 1558 1559 if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes 1560 || (mFlags & PREPARE_CANCELLED)) { 1561 break; 1562 } 1563 1564 usleep(200000); 1565 } 1566 1567 mLock.lock(); 1568 1569 if (mFlags & PREPARE_CANCELLED) { 1570 LOGI("Prepare cancelled while waiting for initial cache fill."); 1571 return UNKNOWN_ERROR; 1572 } 1573 } else if (!strncasecmp(mUri.string(), "httplive://", 11)) { 1574 String8 uri("http://"); 1575 uri.append(mUri.string() + 11); 1576 1577 if (mLooper == NULL) { 1578 mLooper = new ALooper; 1579 mLooper->setName("httplive"); 1580 mLooper->start(); 1581 } 1582 1583 mLiveSession = new LiveSession; 1584 mLooper->registerHandler(mLiveSession); 1585 1586 mLiveSession->connect(uri.string()); 1587 dataSource = mLiveSession->getDataSource(); 1588 1589 sp<MediaExtractor> extractor = 1590 MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); 1591 1592 static_cast<MPEG2TSExtractor *>(extractor.get()) 1593 ->setLiveSession(mLiveSession); 1594 1595 return setDataSource_l(extractor); 1596 } else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) { 1597 if (mLooper == NULL) { 1598 mLooper = new ALooper; 1599 mLooper->setName("gtalk rtp"); 1600 mLooper->start( 1601 false /* runOnCallingThread */, 1602 false /* canCallJava */, 1603 PRIORITY_HIGHEST); 1604 } 1605 1606 const char *startOfCodecString = &mUri.string()[13]; 1607 const char *startOfSlash1 = strchr(startOfCodecString, '/'); 1608 if (startOfSlash1 == NULL) { 1609 return BAD_VALUE; 1610 } 1611 const char *startOfWidthString = &startOfSlash1[1]; 1612 const char *startOfSlash2 = strchr(startOfWidthString, '/'); 1613 if (startOfSlash2 == NULL) { 1614 return BAD_VALUE; 1615 } 1616 const char *startOfHeightString = &startOfSlash2[1]; 1617 1618 String8 codecString(startOfCodecString, startOfSlash1 - startOfCodecString); 1619 String8 widthString(startOfWidthString, startOfSlash2 - startOfWidthString); 1620 String8 heightString(startOfHeightString); 1621 1622#if 0 1623 mRTPPusher = new UDPPusher("/data/misc/rtpout.bin", 5434); 1624 mLooper->registerHandler(mRTPPusher); 1625 1626 mRTCPPusher = new UDPPusher("/data/misc/rtcpout.bin", 5435); 1627 mLooper->registerHandler(mRTCPPusher); 1628#endif 1629 1630 mRTPSession = new ARTPSession; 1631 mLooper->registerHandler(mRTPSession); 1632 1633#if 0 1634 // My AMR SDP 1635 static const char *raw = 1636 "v=0\r\n" 1637 "o=- 64 233572944 IN IP4 127.0.0.0\r\n" 1638 "s=QuickTime\r\n" 1639 "t=0 0\r\n" 1640 "a=range:npt=0-315\r\n" 1641 "a=isma-compliance:2,2.0,2\r\n" 1642 "m=audio 5434 RTP/AVP 97\r\n" 1643 "c=IN IP4 127.0.0.1\r\n" 1644 "b=AS:30\r\n" 1645 "a=rtpmap:97 AMR/8000/1\r\n" 1646 "a=fmtp:97 octet-align\r\n"; 1647#elif 1 1648 String8 sdp; 1649 sdp.appendFormat( 1650 "v=0\r\n" 1651 "o=- 64 233572944 IN IP4 127.0.0.0\r\n" 1652 "s=QuickTime\r\n" 1653 "t=0 0\r\n" 1654 "a=range:npt=0-315\r\n" 1655 "a=isma-compliance:2,2.0,2\r\n" 1656 "m=video 5434 RTP/AVP 97\r\n" 1657 "c=IN IP4 127.0.0.1\r\n" 1658 "b=AS:30\r\n" 1659 "a=rtpmap:97 %s/90000\r\n" 1660 "a=cliprect:0,0,%s,%s\r\n" 1661 "a=framesize:97 %s-%s\r\n", 1662 1663 codecString.string(), 1664 heightString.string(), widthString.string(), 1665 widthString.string(), heightString.string() 1666 ); 1667 const char *raw = sdp.string(); 1668 1669#endif 1670 1671 sp<ASessionDescription> desc = new ASessionDescription; 1672 CHECK(desc->setTo(raw, strlen(raw))); 1673 1674 CHECK_EQ(mRTPSession->setup(desc), (status_t)OK); 1675 1676 if (mRTPPusher != NULL) { 1677 mRTPPusher->start(); 1678 } 1679 1680 if (mRTCPPusher != NULL) { 1681 mRTCPPusher->start(); 1682 } 1683 1684 CHECK_EQ(mRTPSession->countTracks(), 1u); 1685 sp<MediaSource> source = mRTPSession->trackAt(0); 1686 1687#if 0 1688 bool eos; 1689 while (((APacketSource *)source.get()) 1690 ->getQueuedDuration(&eos) < 5000000ll && !eos) { 1691 usleep(100000ll); 1692 } 1693#endif 1694 1695 const char *mime; 1696 CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime)); 1697 1698 if (!strncasecmp("video/", mime, 6)) { 1699 setVideoSource(source); 1700 } else { 1701 CHECK(!strncasecmp("audio/", mime, 6)); 1702 setAudioSource(source); 1703 } 1704 1705 mExtractorFlags = MediaExtractor::CAN_PAUSE; 1706 1707 return OK; 1708 } else if (!strncasecmp("rtsp://", mUri.string(), 7)) { 1709 if (mLooper == NULL) { 1710 mLooper = new ALooper; 1711 mLooper->setName("rtsp"); 1712 mLooper->start(); 1713 } 1714 mRTSPController = new ARTSPController(mLooper); 1715 status_t err = mRTSPController->connect(mUri.string()); 1716 1717 LOGI("ARTSPController::connect returned %d", err); 1718 1719 if (err != OK) { 1720 mRTSPController.clear(); 1721 return err; 1722 } 1723 1724 sp<MediaExtractor> extractor = mRTSPController.get(); 1725 return setDataSource_l(extractor); 1726 } else { 1727 dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); 1728 } 1729 1730 if (dataSource == NULL) { 1731 return UNKNOWN_ERROR; 1732 } 1733 1734 sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); 1735 1736 if (extractor == NULL) { 1737 return UNKNOWN_ERROR; 1738 } 1739 1740 dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient); 1741 if (mDecryptHandle != NULL) { 1742 if (RightsStatus::RIGHTS_VALID == mDecryptHandle->status) { 1743 if (DecryptApiType::WV_BASED == mDecryptHandle->decryptApiType) { 1744 LOGD("Setting mCachedSource to NULL for WVM\n"); 1745 mCachedSource.clear(); 1746 } 1747 } else { 1748 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE); 1749 } 1750 } 1751 1752 return setDataSource_l(extractor); 1753} 1754 1755void AwesomePlayer::abortPrepare(status_t err) { 1756 CHECK(err != OK); 1757 1758 if (mIsAsyncPrepare) { 1759 notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); 1760 } 1761 1762 mPrepareResult = err; 1763 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED); 1764 mAsyncPrepareEvent = NULL; 1765 mPreparedCondition.broadcast(); 1766} 1767 1768// static 1769bool AwesomePlayer::ContinuePreparation(void *cookie) { 1770 AwesomePlayer *me = static_cast<AwesomePlayer *>(cookie); 1771 1772 return (me->mFlags & PREPARE_CANCELLED) == 0; 1773} 1774 1775void AwesomePlayer::onPrepareAsyncEvent() { 1776 Mutex::Autolock autoLock(mLock); 1777 1778 if (mFlags & PREPARE_CANCELLED) { 1779 LOGI("prepare was cancelled before doing anything"); 1780 abortPrepare(UNKNOWN_ERROR); 1781 return; 1782 } 1783 1784 if (mUri.size() > 0) { 1785 status_t err = finishSetDataSource_l(); 1786 1787 if (err != OK) { 1788 abortPrepare(err); 1789 return; 1790 } 1791 } 1792 1793 if (mVideoTrack != NULL && mVideoSource == NULL) { 1794 status_t err = initVideoDecoder(); 1795 1796 if (err != OK) { 1797 abortPrepare(err); 1798 return; 1799 } 1800 } 1801 1802 if (mAudioTrack != NULL && mAudioSource == NULL) { 1803 status_t err = initAudioDecoder(); 1804 1805 if (err != OK) { 1806 abortPrepare(err); 1807 return; 1808 } 1809 } 1810 1811 mFlags |= PREPARING_CONNECTED; 1812 1813 if (mCachedSource != NULL || mRTSPController != NULL) { 1814 postBufferingEvent_l(); 1815 } else { 1816 finishAsyncPrepare_l(); 1817 } 1818} 1819 1820void AwesomePlayer::finishAsyncPrepare_l() { 1821 if (mIsAsyncPrepare) { 1822 if (mVideoSource == NULL) { 1823 notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); 1824 } else { 1825 notifyVideoSize_l(); 1826 } 1827 1828 notifyListener_l(MEDIA_PREPARED); 1829 } 1830 1831 mPrepareResult = OK; 1832 mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED); 1833 mFlags |= PREPARED; 1834 mAsyncPrepareEvent = NULL; 1835 mPreparedCondition.broadcast(); 1836} 1837 1838uint32_t AwesomePlayer::flags() const { 1839 return mExtractorFlags; 1840} 1841 1842void AwesomePlayer::postAudioEOS() { 1843 postCheckAudioStatusEvent_l(); 1844} 1845 1846void AwesomePlayer::postAudioSeekComplete() { 1847 postCheckAudioStatusEvent_l(); 1848} 1849 1850} // namespace android 1851