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