am 2332cd8c: Merge "DO NOT MERGE: Cherry picked hacks to better hide A/V sync issues." into honeycomb

* commit '2332cd8c675628f3bdd6e46a8dd6da639bd7f76e':
  DO NOT MERGE: Cherry picked hacks to better hide A/V sync issues.
This commit is contained in:
Andreas Huber
2011-02-25 15:38:06 -08:00
committed by Android Git Automerger
2 changed files with 154 additions and 62 deletions

View File

@@ -52,7 +52,7 @@
#include "include/LiveSession.h" #include "include/LiveSession.h"
#define USE_SURFACE_ALLOC 1 #define USE_SURFACE_ALLOC 1
#define FRAME_DROP_FREQ 7 #define FRAME_DROP_FREQ 0
namespace android { namespace android {
@@ -477,7 +477,7 @@ void AwesomePlayer::reset_l() {
mTimeSourceDeltaUs = 0; mTimeSourceDeltaUs = 0;
mVideoTimeUs = 0; mVideoTimeUs = 0;
mSeeking = false; mSeeking = NO_SEEK;
mSeekNotificationSent = false; mSeekNotificationSent = false;
mSeekTimeUs = 0; mSeekTimeUs = 0;
@@ -783,25 +783,6 @@ status_t AwesomePlayer::play_l() {
mAudioPlayer = new AudioPlayer(mAudioSink, this); mAudioPlayer = new AudioPlayer(mAudioSink, this);
mAudioPlayer->setSource(mAudioSource); mAudioPlayer->setSource(mAudioSource);
// We've already started the MediaSource in order to enable
// the prefetcher to read its data.
status_t err = mAudioPlayer->start(
true /* sourceAlreadyStarted */);
if (err != OK) {
delete mAudioPlayer;
mAudioPlayer = NULL;
mFlags &= ~(PLAYING | FIRST_FRAME);
if (mDecryptHandle != NULL) {
mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
Playback::STOP, 0);
}
return err;
}
mTimeSource = mAudioPlayer; mTimeSource = mAudioPlayer;
deferredAudioSeek = true; deferredAudioSeek = true;
@@ -809,8 +790,26 @@ status_t AwesomePlayer::play_l() {
mWatchForAudioSeekComplete = false; mWatchForAudioSeekComplete = false;
mWatchForAudioEOS = true; mWatchForAudioEOS = true;
} }
} else { }
mAudioPlayer->resume();
CHECK(!(mFlags & AUDIO_RUNNING));
if (mVideoSource == NULL) {
status_t err = startAudioPlayer_l();
if (err != OK) {
delete mAudioPlayer;
mAudioPlayer = NULL;
mFlags &= ~(PLAYING | FIRST_FRAME);
if (mDecryptHandle != NULL) {
mDrmManagerClient->setPlaybackStatus(
mDecryptHandle, Playback::STOP, 0);
}
return err;
}
} }
} }
@@ -842,6 +841,36 @@ status_t AwesomePlayer::play_l() {
return OK; return OK;
} }
status_t AwesomePlayer::startAudioPlayer_l() {
CHECK(!(mFlags & AUDIO_RUNNING));
if (mAudioSource == NULL || mAudioPlayer == NULL) {
return OK;
}
if (!(mFlags & AUDIOPLAYER_STARTED)) {
mFlags |= AUDIOPLAYER_STARTED;
// We've already started the MediaSource in order to enable
// the prefetcher to read its data.
status_t err = mAudioPlayer->start(
true /* sourceAlreadyStarted */);
if (err != OK) {
notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
return err;
}
} else {
mAudioPlayer->resume();
}
mFlags |= AUDIO_RUNNING;
mWatchForAudioEOS = true;
return OK;
}
void AwesomePlayer::notifyVideoSize_l() { void AwesomePlayer::notifyVideoSize_l() {
sp<MetaData> meta = mVideoSource->getFormat(); sp<MetaData> meta = mVideoSource->getFormat();
@@ -943,7 +972,7 @@ status_t AwesomePlayer::pause_l(bool at_eos) {
cancelPlayerEvents(true /* keepBufferingGoing */); cancelPlayerEvents(true /* keepBufferingGoing */);
if (mAudioPlayer != NULL) { if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
if (at_eos) { if (at_eos) {
// If we played the audio stream to completion we // If we played the audio stream to completion we
// want to make sure that all samples remaining in the audio // want to make sure that all samples remaining in the audio
@@ -952,6 +981,8 @@ status_t AwesomePlayer::pause_l(bool at_eos) {
} else { } else {
mAudioPlayer->pause(); mAudioPlayer->pause();
} }
mFlags &= ~AUDIO_RUNNING;
} }
mFlags &= ~PLAYING; mFlags &= ~PLAYING;
@@ -1009,7 +1040,7 @@ status_t AwesomePlayer::getPosition(int64_t *positionUs) {
if (mRTSPController != NULL) { if (mRTSPController != NULL) {
*positionUs = mRTSPController->getNormalPlayTimeUs(); *positionUs = mRTSPController->getNormalPlayTimeUs();
} }
else if (mSeeking) { else if (mSeeking != NO_SEEK) {
*positionUs = mSeekTimeUs; *positionUs = mSeekTimeUs;
} else if (mVideoSource != NULL) { } else if (mVideoSource != NULL) {
Mutex::Autolock autoLock(mMiscStateLock); Mutex::Autolock autoLock(mMiscStateLock);
@@ -1053,7 +1084,7 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
play_l(); play_l();
} }
mSeeking = true; mSeeking = SEEK;
mSeekNotificationSent = false; mSeekNotificationSent = false;
mSeekTimeUs = timeUs; mSeekTimeUs = timeUs;
mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS); mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
@@ -1072,7 +1103,7 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
} }
void AwesomePlayer::seekAudioIfNecessary_l() { void AwesomePlayer::seekAudioIfNecessary_l() {
if (mSeeking && mVideoSource == NULL && mAudioPlayer != NULL) { if (mSeeking != NO_SEEK && mVideoSource == NULL && mAudioPlayer != NULL) {
mAudioPlayer->seekTo(mSeekTimeUs); mAudioPlayer->seekTo(mSeekTimeUs);
mWatchForAudioSeekComplete = true; mWatchForAudioSeekComplete = true;
@@ -1168,7 +1199,12 @@ status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
} }
void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
if (!mSeeking) { if (mSeeking == SEEK_VIDEO_ONLY) {
mSeeking = NO_SEEK;
return;
}
if (mSeeking == NO_SEEK) {
return; return;
} }
@@ -1179,9 +1215,7 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
// requested seek time instead. // requested seek time instead.
mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs); mAudioPlayer->seekTo(videoTimeUs < 0 ? mSeekTimeUs : videoTimeUs);
mAudioPlayer->resume();
mWatchForAudioSeekComplete = true; mWatchForAudioSeekComplete = true;
mWatchForAudioEOS = true;
} else if (!mSeekNotificationSent) { } else if (!mSeekNotificationSent) {
// If we're playing video only, report seek complete now, // If we're playing video only, report seek complete now,
// otherwise audio player will notify us later. // otherwise audio player will notify us later.
@@ -1189,7 +1223,7 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
} }
mFlags |= FIRST_FRAME; mFlags |= FIRST_FRAME;
mSeeking = false; mSeeking = NO_SEEK;
mSeekNotificationSent = false; mSeekNotificationSent = false;
if (mDecryptHandle != NULL) { if (mDecryptHandle != NULL) {
@@ -1209,13 +1243,13 @@ void AwesomePlayer::onVideoEvent() {
} }
mVideoEventPending = false; mVideoEventPending = false;
if (mSeeking) { if (mSeeking != NO_SEEK) {
if (mVideoBuffer) { if (mVideoBuffer) {
mVideoBuffer->release(); mVideoBuffer->release();
mVideoBuffer = NULL; mVideoBuffer = NULL;
} }
if (mCachedSource != NULL && mAudioSource != NULL) { if (mSeeking == SEEK && mCachedSource != NULL && mAudioSource != NULL) {
// We're going to seek the video source first, followed by // We're going to seek the video source first, followed by
// the audio source. // the audio source.
// In order to avoid jumps in the DataSource offset caused by // In order to avoid jumps in the DataSource offset caused by
@@ -1224,8 +1258,10 @@ void AwesomePlayer::onVideoEvent() {
// locations, we'll "pause" the audio source, causing it to // locations, we'll "pause" the audio source, causing it to
// stop reading input data until a subsequent seek. // stop reading input data until a subsequent seek.
if (mAudioPlayer != NULL) { if (mAudioPlayer != NULL && (mFlags & AUDIO_RUNNING)) {
mAudioPlayer->pause(); mAudioPlayer->pause();
mFlags &= ~AUDIO_RUNNING;
} }
mAudioSource->pause(); mAudioSource->pause();
} }
@@ -1233,11 +1269,14 @@ void AwesomePlayer::onVideoEvent() {
if (!mVideoBuffer) { if (!mVideoBuffer) {
MediaSource::ReadOptions options; MediaSource::ReadOptions options;
if (mSeeking) { if (mSeeking != NO_SEEK) {
LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6); LOGV("seeking to %lld us (%.2f secs)", mSeekTimeUs, mSeekTimeUs / 1E6);
options.setSeekTo( options.setSeekTo(
mSeekTimeUs, MediaSource::ReadOptions::SEEK_CLOSEST_SYNC); mSeekTimeUs,
mSeeking == SEEK_VIDEO_ONLY
? MediaSource::ReadOptions::SEEK_NEXT_SYNC
: MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
} }
for (;;) { for (;;) {
status_t err = mVideoSource->read(&mVideoBuffer, &options); status_t err = mVideoSource->read(&mVideoBuffer, &options);
@@ -1261,7 +1300,7 @@ void AwesomePlayer::onVideoEvent() {
// So video playback is complete, but we may still have // So video playback is complete, but we may still have
// a seek request pending that needs to be applied // a seek request pending that needs to be applied
// to the audio track. // to the audio track.
if (mSeeking) { if (mSeeking != NO_SEEK) {
LOGV("video stream ended while seeking!"); LOGV("video stream ended while seeking!");
} }
finishSeekIfNecessary(-1); finishSeekIfNecessary(-1);
@@ -1287,14 +1326,29 @@ void AwesomePlayer::onVideoEvent() {
int64_t timeUs; int64_t timeUs;
CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
if (mSeeking == SEEK_VIDEO_ONLY) {
if (mSeekTimeUs > timeUs) {
LOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
mSeekTimeUs, timeUs);
}
}
{ {
Mutex::Autolock autoLock(mMiscStateLock); Mutex::Autolock autoLock(mMiscStateLock);
mVideoTimeUs = timeUs; mVideoTimeUs = timeUs;
} }
bool wasSeeking = mSeeking; SeekType wasSeeking = mSeeking;
finishSeekIfNecessary(timeUs); finishSeekIfNecessary(timeUs);
if (mAudioPlayer != NULL && !(mFlags & AUDIO_RUNNING)) {
status_t err = startAudioPlayer_l();
if (err != OK) {
LOGE("Startung the audio player failed w/ err %d", err);
return;
}
}
TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource; TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
if (mFlags & FIRST_FRAME) { if (mFlags & FIRST_FRAME) {
@@ -1309,41 +1363,68 @@ void AwesomePlayer::onVideoEvent() {
mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; mTimeSourceDeltaUs = realTimeUs - mediaTimeUs;
} }
int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; if (wasSeeking == SEEK_VIDEO_ONLY) {
int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
int64_t latenessUs = nowUs - timeUs; int64_t latenessUs = nowUs - timeUs;
if (wasSeeking) { if (latenessUs > 0) {
LOGI("after SEEK_VIDEO_ONLY we're late by %.2f secs", latenessUs / 1E6);
}
}
if (wasSeeking == NO_SEEK) {
// Let's display the first frame after seeking right away. // Let's display the first frame after seeking right away.
latenessUs = 0;
}
if (mRTPSession != NULL) { int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs;
// We'll completely ignore timestamps for gtalk videochat
// and we'll play incoming video as fast as we get it. int64_t latenessUs = nowUs - timeUs;
latenessUs = 0;
} if (latenessUs > 500000ll
&& mRTSPController == NULL
&& mAudioPlayer != NULL
&& mAudioPlayer->getMediaTimeMapping(
&realTimeUs, &mediaTimeUs)) {
LOGI("we're much too late (%.2f secs), video skipping ahead",
latenessUs / 1E6);
if (latenessUs > 40000) {
// We're more than 40ms late.
LOGV("we're late by %lld us (%.2f secs)", latenessUs, latenessUs / 1E6);
if ( mSinceLastDropped > FRAME_DROP_FREQ)
{
LOGV("we're late by %lld us (%.2f secs) dropping one after %d frames", latenessUs, latenessUs / 1E6, mSinceLastDropped);
mSinceLastDropped = 0;
mVideoBuffer->release(); mVideoBuffer->release();
mVideoBuffer = NULL; mVideoBuffer = NULL;
mSeeking = SEEK_VIDEO_ONLY;
mSeekTimeUs = mediaTimeUs;
postVideoEvent_l(); postVideoEvent_l();
return; return;
} }
}
if (latenessUs < -10000) { if (latenessUs > 40000) {
// We're more than 10ms early. // We're more than 40ms late.
postVideoEvent_l(10000); LOGV("we're late by %lld us (%.2f secs)",
return; latenessUs, latenessUs / 1E6);
if ( mSinceLastDropped > FRAME_DROP_FREQ)
{
LOGV("we're late by %lld us (%.2f secs) dropping one "
"after %d frames",
latenessUs, latenessUs / 1E6, mSinceLastDropped);
mSinceLastDropped = 0;
mVideoBuffer->release();
mVideoBuffer = NULL;
postVideoEvent_l();
return;
}
}
if (latenessUs < -10000) {
// We're more than 10ms early.
postVideoEvent_l(10000);
return;
}
} }
if (mVideoRendererIsPreview || mVideoRenderer == NULL) { if (mVideoRendererIsPreview || mVideoRenderer == NULL) {
@@ -1424,7 +1505,7 @@ void AwesomePlayer::onCheckAudioStatus() {
mSeekNotificationSent = true; mSeekNotificationSent = true;
} }
mSeeking = false; mSeeking = NO_SEEK;
} }
status_t finalStatus; status_t finalStatus;

View File

@@ -119,6 +119,9 @@ private:
// sufficient data to begin playback and finish the preparation phase // sufficient data to begin playback and finish the preparation phase
// for good. // for good.
PREPARING_CONNECTED = 2048, PREPARING_CONNECTED = 2048,
AUDIO_RUNNING = 8192,
AUDIOPLAYER_STARTED = 16384,
}; };
mutable Mutex mLock; mutable Mutex mLock;
@@ -160,7 +163,13 @@ private:
int64_t mTimeSourceDeltaUs; int64_t mTimeSourceDeltaUs;
int64_t mVideoTimeUs; int64_t mVideoTimeUs;
bool mSeeking; enum SeekType {
NO_SEEK,
SEEK,
SEEK_VIDEO_ONLY
};
SeekType mSeeking;
bool mSeekNotificationSent; bool mSeekNotificationSent;
int64_t mSeekTimeUs; int64_t mSeekTimeUs;
@@ -256,6 +265,8 @@ private:
void finishSeekIfNecessary(int64_t videoTimeUs); void finishSeekIfNecessary(int64_t videoTimeUs);
void ensureCacheIsFetching_l(); void ensureCacheIsFetching_l();
status_t startAudioPlayer_l();
AwesomePlayer(const AwesomePlayer &); AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &); AwesomePlayer &operator=(const AwesomePlayer &);
}; };