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