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