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