AwesomePlayer.cpp revision 08411b75d4c30ce26180639f158e2f33d190eee8
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 // Some decoders, notably the PV AVC software decoder 548 // return spurious empty buffers that we just want to ignore. 549 550 mVideoBuffer->release(); 551 mVideoBuffer = NULL; 552 continue; 553 } 554 555 break; 556 } 557 } 558 559 int64_t timeUs; 560 CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); 561 562 mVideoTimeUs = timeUs; 563 564 if (mSeeking) { 565 if (mAudioPlayer != NULL) { 566 LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6); 567 568 mAudioPlayer->seekTo(timeUs); 569 } else { 570 // If we're playing video only, report seek complete now, 571 // otherwise audio player will notify us later. 572 if (mListener != NULL) { 573 mListener->sendEvent(MEDIA_SEEK_COMPLETE); 574 } 575 } 576 577 mFlags |= FIRST_FRAME; 578 mSeeking = false; 579 } 580 581 if (mFlags & FIRST_FRAME) { 582 mFlags &= ~FIRST_FRAME; 583 584 mTimeSourceDeltaUs = mTimeSource->getRealTimeUs() - timeUs; 585 } 586 587 int64_t realTimeUs, mediaTimeUs; 588 if (mAudioPlayer != NULL 589 && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { 590 mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; 591 } 592 593 int64_t nowUs = mTimeSource->getRealTimeUs() - mTimeSourceDeltaUs; 594 595 int64_t latenessUs = nowUs - timeUs; 596 597 if (latenessUs > 40000) { 598 // We're more than 40ms late. 599 LOGI("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6); 600 601 mVideoBuffer->release(); 602 mVideoBuffer = NULL; 603 604 postVideoEvent_l(); 605 return; 606 } 607 608 if (latenessUs < -10000) { 609 // We're more than 10ms early. 610 611 postVideoEvent_l(10000); 612 return; 613 } 614 615 void *id; 616 if (mVideoBuffer->meta_data()->findPointer(kKeyBufferID, &id)) { 617 mVideoRenderer->render((IOMX::buffer_id)id); 618 } 619 620 if (mLastVideoBuffer) { 621 mLastVideoBuffer->release(); 622 mLastVideoBuffer = NULL; 623 } 624 mLastVideoBuffer = mVideoBuffer; 625 mVideoBuffer = NULL; 626 627 postVideoEvent_l(); 628} 629 630void AwesomePlayer::postVideoEvent_l(int64_t delayUs) { 631 if (mVideoEventPending) { 632 return; 633 } 634 635 mVideoEventPending = true; 636 mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs); 637} 638 639void AwesomePlayer::postStreamDoneEvent_l() { 640 if (mStreamDoneEventPending) { 641 return; 642 } 643 mStreamDoneEventPending = true; 644 mQueue.postEvent(mStreamDoneEvent); 645} 646 647} // namespace android 648 649