AwesomePlayer.cpp revision fd4a8e09a54469bbccea6248f84319a1eb78765e
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 "include/AwesomePlayer.h" 22 23#include <binder/IPCThreadState.h> 24#include <media/stagefright/AudioPlayer.h> 25#include <media/stagefright/DataSource.h> 26#include <media/stagefright/FileSource.h> 27#include <media/stagefright/MediaBuffer.h> 28#include <media/stagefright/MediaExtractor.h> 29#include <media/stagefright/MediaDebug.h> 30#include <media/stagefright/MediaSource.h> 31#include <media/stagefright/MetaData.h> 32#include <media/stagefright/OMXCodec.h> 33 34namespace android { 35 36struct AwesomeEvent : public TimedEventQueue::Event { 37 AwesomeEvent(AwesomePlayer *player, int32_t code) 38 : mPlayer(player), 39 mCode(code) { 40 } 41 42protected: 43 virtual ~AwesomeEvent() {} 44 45 virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { 46 mPlayer->onEvent(mCode); 47 } 48 49private: 50 AwesomePlayer *mPlayer; 51 int32_t mCode; 52 53 AwesomeEvent(const AwesomeEvent &); 54 AwesomeEvent &operator=(const AwesomeEvent &); 55}; 56 57AwesomePlayer::AwesomePlayer() 58 : mTimeSource(NULL), 59 mAudioPlayer(NULL), 60 mLastVideoBuffer(NULL), 61 mVideoBuffer(NULL) { 62 CHECK_EQ(mClient.connect(), OK); 63 64 DataSource::RegisterDefaultSniffers(); 65 66 mVideoEvent = new AwesomeEvent(this, 0); 67 mVideoEventPending = false; 68 mStreamDoneEvent = new AwesomeEvent(this, 1); 69 mStreamDoneEventPending = false; 70 71 mQueue.start(); 72 73 reset(); 74} 75 76AwesomePlayer::~AwesomePlayer() { 77 mQueue.stop(); 78 79 reset(); 80 81 mClient.disconnect(); 82} 83 84void AwesomePlayer::cancelPlayerEvents() { 85 mQueue.cancelEvent(mVideoEvent->eventID()); 86 mVideoEventPending = false; 87 mQueue.cancelEvent(mStreamDoneEvent->eventID()); 88 mStreamDoneEventPending = false; 89} 90 91void AwesomePlayer::setListener(const sp<MediaPlayerBase> &listener) { 92 Mutex::Autolock autoLock(mLock); 93 mListener = listener; 94} 95 96status_t AwesomePlayer::setDataSource(const char *uri) { 97 Mutex::Autolock autoLock(mLock); 98 99 reset_l(); 100 101 sp<MediaExtractor> extractor = MediaExtractor::CreateFromURI(uri); 102 103 if (extractor == NULL) { 104 return UNKNOWN_ERROR; 105 } 106 107 return setDataSource_l(extractor); 108} 109 110status_t AwesomePlayer::setDataSource( 111 int fd, int64_t offset, int64_t length) { 112 Mutex::Autolock autoLock(mLock); 113 114 reset_l(); 115 116 sp<DataSource> source = new FileSource(fd, offset, length); 117 118 status_t err = source->initCheck(); 119 120 if (err != OK) { 121 return err; 122 } 123 124 sp<MediaExtractor> extractor = MediaExtractor::Create(source); 125 126 if (extractor == NULL) { 127 return UNKNOWN_ERROR; 128 } 129 130 return setDataSource_l(extractor); 131} 132 133status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { 134 reset_l(); 135 136 bool haveAudio = false; 137 bool haveVideo = false; 138 for (size_t i = 0; i < extractor->countTracks(); ++i) { 139 sp<MetaData> meta = extractor->getTrackMetaData(i); 140 141 const char *mime; 142 CHECK(meta->findCString(kKeyMIMEType, &mime)); 143 144 if (!haveVideo && !strncasecmp(mime, "video/", 6)) { 145 if (setVideoSource(extractor->getTrack(i)) == OK) { 146 haveVideo = true; 147 } 148 } else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) { 149 if (setAudioSource(extractor->getTrack(i)) == OK) { 150 haveAudio = true; 151 } 152 } 153 154 if (haveAudio && haveVideo) { 155 break; 156 } 157 } 158 159 return !haveAudio && !haveVideo ? UNKNOWN_ERROR : OK; 160} 161 162void AwesomePlayer::reset() { 163 Mutex::Autolock autoLock(mLock); 164 reset_l(); 165} 166 167void AwesomePlayer::reset_l() { 168 cancelPlayerEvents(); 169 170 if (mLastVideoBuffer) { 171 mLastVideoBuffer->release(); 172 mLastVideoBuffer = NULL; 173 } 174 175 if (mVideoBuffer) { 176 mVideoBuffer->release(); 177 mVideoBuffer = NULL; 178 } 179 180 if (mVideoSource != NULL) { 181 mVideoSource->stop(); 182 mVideoSource.clear(); 183 } 184 185 mAudioSource.clear(); 186 187 if (mTimeSource != mAudioPlayer) { 188 delete mTimeSource; 189 } 190 mTimeSource = NULL; 191 192 delete mAudioPlayer; 193 mAudioPlayer = NULL; 194 195 mVideoRenderer.clear(); 196 197 mDurationUs = -1; 198 mFlags = 0; 199 mVideoWidth = mVideoHeight = -1; 200 mTimeSourceDeltaUs = 0; 201 mVideoTimeUs = 0; 202 203 mSeeking = false; 204 mSeekTimeUs = 0; 205} 206 207// static 208void AwesomePlayer::AudioNotify(void *_me, int what) { 209 AwesomePlayer *me = (AwesomePlayer *)_me; 210 211 Mutex::Autolock autoLock(me->mLock); 212 213 switch (what) { 214 case AudioPlayer::REACHED_EOS: 215 me->postStreamDoneEvent_l(); 216 break; 217 218 case AudioPlayer::SEEK_COMPLETE: 219 { 220 if (me->mListener != NULL) { 221 me->mListener->sendEvent(MEDIA_SEEK_COMPLETE); 222 } 223 224 break; 225 } 226 227 default: 228 CHECK(!"should not be here."); 229 break; 230 } 231} 232 233void AwesomePlayer::onStreamDone() { 234 // Posted whenever any stream finishes playing. 235 236 Mutex::Autolock autoLock(mLock); 237 mStreamDoneEventPending = false; 238 239 if (mFlags & LOOPING) { 240 seekTo_l(0); 241 242 if (mVideoRenderer != NULL) { 243 postVideoEvent_l(); 244 } 245 } else { 246 if (mListener != NULL) { 247 mListener->sendEvent(MEDIA_PLAYBACK_COMPLETE); 248 } 249 250 pause_l(); 251 } 252} 253 254status_t AwesomePlayer::play() { 255 Mutex::Autolock autoLock(mLock); 256 257 if (mFlags & PLAYING) { 258 return OK; 259 } 260 261 mFlags |= PLAYING; 262 mFlags |= FIRST_FRAME; 263 264 bool deferredAudioSeek = false; 265 266 if (mAudioSource != NULL) { 267 if (mAudioPlayer == NULL) { 268 if (mAudioSink != NULL) { 269 mAudioPlayer = new AudioPlayer(mAudioSink); 270 271 mAudioPlayer->setListenerCallback( 272 &AwesomePlayer::AudioNotify, this); 273 274 mAudioPlayer->setSource(mAudioSource); 275 mAudioPlayer->start(); 276 277 delete mTimeSource; 278 mTimeSource = mAudioPlayer; 279 280 deferredAudioSeek = true; 281 } 282 } else { 283 mAudioPlayer->resume(); 284 } 285 } 286 287 if (mTimeSource == NULL && mAudioPlayer == NULL) { 288 mTimeSource = new SystemTimeSource; 289 } 290 291 if (mVideoSource != NULL) { 292 if (mVideoRenderer == NULL) { 293 initRenderer_l(); 294 } 295 296 if (mVideoRenderer != NULL) { 297 // Kick off video playback 298 postVideoEvent_l(); 299 } 300 } 301 302 if (deferredAudioSeek) { 303 // If there was a seek request while we were paused 304 // and we're just starting up again, honor the request now. 305 seekAudioIfNecessary_l(); 306 } 307 308 return OK; 309} 310 311void AwesomePlayer::initRenderer_l() { 312 if (mISurface != NULL) { 313 sp<MetaData> meta = mVideoSource->getFormat(); 314 315 int32_t format; 316 const char *component; 317 int32_t decodedWidth, decodedHeight; 318 CHECK(meta->findInt32(kKeyColorFormat, &format)); 319 CHECK(meta->findCString(kKeyDecoderComponent, &component)); 320 CHECK(meta->findInt32(kKeyWidth, &decodedWidth)); 321 CHECK(meta->findInt32(kKeyHeight, &decodedHeight)); 322 323 mVideoRenderer.clear(); 324 325 // Must ensure that mVideoRenderer's destructor is actually executed 326 // before creating a new one. 327 IPCThreadState::self()->flushCommands(); 328 329 mVideoRenderer = 330 mClient.interface()->createRenderer( 331 mISurface, component, 332 (OMX_COLOR_FORMATTYPE)format, 333 decodedWidth, decodedHeight, 334 mVideoWidth, mVideoHeight); 335 } 336} 337 338status_t AwesomePlayer::pause() { 339 Mutex::Autolock autoLock(mLock); 340 return pause_l(); 341} 342 343status_t AwesomePlayer::pause_l() { 344 if (!(mFlags & PLAYING)) { 345 return OK; 346 } 347 348 cancelPlayerEvents(); 349 350 if (mAudioPlayer != NULL) { 351 mAudioPlayer->pause(); 352 } 353 354 mFlags &= ~PLAYING; 355 356 return OK; 357} 358 359bool AwesomePlayer::isPlaying() const { 360 Mutex::Autolock autoLock(mLock); 361 362 return mFlags & PLAYING; 363} 364 365void AwesomePlayer::setISurface(const sp<ISurface> &isurface) { 366 Mutex::Autolock autoLock(mLock); 367 368 mISurface = isurface; 369} 370 371void AwesomePlayer::setAudioSink( 372 const sp<MediaPlayerBase::AudioSink> &audioSink) { 373 Mutex::Autolock autoLock(mLock); 374 375 mAudioSink = audioSink; 376} 377 378status_t AwesomePlayer::setLooping(bool shouldLoop) { 379 Mutex::Autolock autoLock(mLock); 380 381 mFlags = mFlags & ~LOOPING; 382 383 if (shouldLoop) { 384 mFlags |= LOOPING; 385 } 386 387 return OK; 388} 389 390status_t AwesomePlayer::getDuration(int64_t *durationUs) { 391 Mutex::Autolock autoLock(mLock); 392 393 if (mDurationUs < 0) { 394 return UNKNOWN_ERROR; 395 } 396 397 *durationUs = mDurationUs; 398 399 return OK; 400} 401 402status_t AwesomePlayer::getPosition(int64_t *positionUs) { 403 Mutex::Autolock autoLock(mLock); 404 405 if (mVideoRenderer != NULL) { 406 *positionUs = mVideoTimeUs; 407 } else if (mAudioPlayer != NULL) { 408 *positionUs = mAudioPlayer->getMediaTimeUs(); 409 } else { 410 *positionUs = 0; 411 } 412 413 return OK; 414} 415 416status_t AwesomePlayer::seekTo(int64_t timeUs) { 417 Mutex::Autolock autoLock(mLock); 418 return seekTo_l(timeUs); 419} 420 421status_t AwesomePlayer::seekTo_l(int64_t timeUs) { 422 mSeeking = true; 423 mSeekTimeUs = timeUs; 424 425 seekAudioIfNecessary_l(); 426 427 return OK; 428} 429 430void AwesomePlayer::seekAudioIfNecessary_l() { 431 if (mSeeking && mVideoRenderer == NULL && mAudioPlayer != NULL) { 432 mAudioPlayer->seekTo(mSeekTimeUs); 433 434 mSeeking = false; 435 } 436} 437 438status_t AwesomePlayer::getVideoDimensions( 439 int32_t *width, int32_t *height) const { 440 Mutex::Autolock autoLock(mLock); 441 442 if (mVideoWidth < 0 || mVideoHeight < 0) { 443 return UNKNOWN_ERROR; 444 } 445 446 *width = mVideoWidth; 447 *height = mVideoHeight; 448 449 return OK; 450} 451 452status_t AwesomePlayer::setAudioSource(const sp<MediaSource> &source) { 453 if (source == NULL) { 454 return UNKNOWN_ERROR; 455 } 456 457 mAudioSource = OMXCodec::Create( 458 mClient.interface(), source->getFormat(), 459 false, // createEncoder 460 source); 461 462 if (mAudioSource != NULL) { 463 int64_t durationUs; 464 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { 465 if (mDurationUs < 0 || durationUs > mDurationUs) { 466 mDurationUs = durationUs; 467 } 468 } 469 } 470 471 return mAudioSource != NULL ? OK : UNKNOWN_ERROR; 472} 473 474status_t AwesomePlayer::setVideoSource(const sp<MediaSource> &source) { 475 if (source == NULL) { 476 return UNKNOWN_ERROR; 477 } 478 479 mVideoSource = OMXCodec::Create( 480 mClient.interface(), source->getFormat(), 481 false, // createEncoder 482 source); 483 484 if (mVideoSource != NULL) { 485 int64_t durationUs; 486 if (source->getFormat()->findInt64(kKeyDuration, &durationUs)) { 487 if (mDurationUs < 0 || durationUs > mDurationUs) { 488 mDurationUs = durationUs; 489 } 490 } 491 492 CHECK(source->getFormat()->findInt32(kKeyWidth, &mVideoWidth)); 493 CHECK(source->getFormat()->findInt32(kKeyHeight, &mVideoHeight)); 494 495 mVideoSource->start(); 496 } 497 498 return mVideoSource != NULL ? OK : UNKNOWN_ERROR; 499} 500 501void AwesomePlayer::onEvent(int32_t code) { 502 if (code == 1) { 503 onStreamDone(); 504 return; 505 } 506 507 Mutex::Autolock autoLock(mLock); 508 mVideoEventPending = false; 509 510 if (mSeeking) { 511 if (mLastVideoBuffer) { 512 mLastVideoBuffer->release(); 513 mLastVideoBuffer = NULL; 514 } 515 516 if (mVideoBuffer) { 517 mVideoBuffer->release(); 518 mVideoBuffer = NULL; 519 } 520 } 521 522 if (!mVideoBuffer) { 523 MediaSource::ReadOptions options; 524 if (mSeeking) { 525 LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); 526 527 options.setSeekTo(mSeekTimeUs); 528 } 529 for (;;) { 530 status_t err = mVideoSource->read(&mVideoBuffer, &options); 531 532 if (err != OK) { 533 CHECK_EQ(mVideoBuffer, NULL); 534 535 if (err == INFO_FORMAT_CHANGED) { 536 LOGV("VideoSource signalled format change."); 537 538 initRenderer_l(); 539 continue; 540 } 541 542 postStreamDoneEvent_l(); 543 return; 544 } 545 546 if (mVideoBuffer->range_length() == 0) { 547 mVideoBuffer->release(); 548 mVideoBuffer = NULL; 549 continue; 550 } 551 552 break; 553 } 554 } 555 556 int64_t timeUs; 557 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 558 559 mVideoTimeUs = timeUs; 560 561 if (mSeeking) { 562 if (mAudioPlayer != NULL) { 563 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6); 564 565 mAudioPlayer->seekTo(timeUs); 566 } else { 567 // If we're playing video only, report seek complete now, 568 // otherwise audio player will notify us later. 569 if (mListener != NULL) { 570 mListener->sendEvent(MEDIA_SEEK_COMPLETE); 571 } 572 } 573 574 mFlags |= FIRST_FRAME; 575 mSeeking = false; 576 } 577 578 if (mFlags & FIRST_FRAME) { 579 mFlags &= ~FIRST_FRAME; 580 581 mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs; 582 } 583 584 int64_t realTimeUs, mediaTimeUs; 585 if (mAudioPlayer != NULL 586 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 587 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 588 } 589 590 int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs; 591 592 int64_t latenessUs = nowUs - timeUs; 593 594 if (latenessUs > 40000) { 595 // We're more than 40ms late. 596 LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6); 597 598 mVideoBuffer->release(); 599 mVideoBuffer = NULL; 600 601 postVideoEvent_l(); 602 return; 603 } 604 605 if (latenessUs < -10000) { 606 // We're more than 10ms early. 607 608 postVideoEvent_l(10000); 609 return; 610 } 611 612 void *id; 613 if (mVideoBuffer->meta_data()->findPointer(kKeyBufferID, &id)) { 614 mVideoRenderer->render((IOMX::buffer_id)id); 615 } 616 617 if (mLastVideoBuffer) { 618 mLastVideoBuffer->release(); 619 mLastVideoBuffer = NULL; 620 } 621 mLastVideoBuffer = mVideoBuffer; 622 mVideoBuffer = NULL; 623 624 postVideoEvent_l(); 625} 626 627void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 628 if (mVideoEventPending) { 629 return; 630 } 631 632 mVideoEventPending = true; 633 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 634} 635 636void AwesomePlayer::postStreamDoneEvent_l() { 637 if (mStreamDoneEventPending) { 638 return; 639 } 640 mStreamDoneEventPending = true; 641 mQueue.postEvent(mStreamDoneEvent); 642} 643 644} // namespace android 645 646