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