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