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