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