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