diff options
author | Alexy Joseph <alexyj@codeaurora.org> | 2012-12-22 00:58:48 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit@review.cyanogenmod.com> | 2013-01-26 19:49:25 -0800 |
commit | d7a251d1422895694f71764678ff48d021224752 (patch) | |
tree | 80205dc0b9aece93abd5e8ba25d0e2a5464606f5 /media/libstagefright/AwesomePlayer.cpp | |
parent | 391bf29ad1177d973cb6a9daea13677373204176 (diff) | |
download | frameworks_av-d7a251d1422895694f71764678ff48d021224752.zip frameworks_av-d7a251d1422895694f71764678ff48d021224752.tar.gz frameworks_av-d7a251d1422895694f71764678ff48d021224752.tar.bz2 |
libstagefright: Collection of fixes for TunnelPlayer
-Handling of EOS, and triggering EOS was wrong
in TunnelPlayer. Seeking when EOS was posted
to the HAL was wrong. EOS should
not be posted till seek is complete
-Also, EOS should not be posted to
the app if we are seeking
-Player should wake up when seeked,
even after EOS was posted from player
to HAL
-Fixed this issue by cleaning up the code for EOS
-Disable tunnel mode playback for streaming use cases
to avoid jittery playback
Change-Id: I21699d2d5874bde6cbfe549ce0251b252e9a4090
CRs-Fixed: 433346
CRs-Fixed: 432233
CRs-Fixed: 429868
libstagefright: Add new mime for QC TS container
- Add new mime type for TS container that is sniffed by extended
extractor. This is needed for media extractor to determine which
parser to create.
Change-Id: I18dcebbbf3b31cea7db29a4dd65385638343bec1
libstagefright: Use software decoder for ADTS content.
Use software decoder for widevine content which uses ADTS
format.
CRs-fixed: 431096
(cherry picked from commit 3edf2e703bcdc47f122864865056d5cb65b7ab43)
Change-Id: I50eba673ddd6ec2bbb737577978e61902ff68d13
audioflinger: Fix to release wakelock after closeoutput
-In DirectTrack destructor, closeOutput is called after
releaseWakelock is done. This may sometimes result in
power collapse happening even before actual close
sequence of Audio path is completed and will result
in high power consumption.
-Release wakelock only after closeOutput is done
in directtrack destructor.
CRs-fixed: 438179
Change-Id: Ibe103804daf2cb09bade998d6d34c3a34508dd09
libstagefright: Add support to change clip duration to enable LPA
Added support to change the clip duration threshold value for LPA
playback. A new system property 'lpa.min_duration' has been added
which controls the minimum clip length for enabling LPA.
The default threshold value has been retained as 60sec.
Change-Id: I6a8be6d6bf67495977d8c75e5be14723a31353b1
frameworks/av: Skip tunnel mode for playback through AudioCache
In the use case of playback using SoundPool, decoded data is
cached from player and further rendered through AudioCache.
Avoid Tunnel mode for the use case AAC format through SoundPool
Change-Id: I21005a5b39f9fb480ae0d525ecb560fec4382620
CRs-Fixed: 437539
frameworks/base: dumpsys rendering statistics for Stagefright
- this adds extra fps statisticis
- report via dumpsys
Change-Id: I7b4d4582c4eb2ccf2d11557844dade92f9e587c0
CRs-Fixed: 435013
libstagefright: Stop extractor source after start in TunnelPlayer
Issue: In the use case of frequent suspend resume during Video
Playback with HDMI Connected, we encounter a scenario where tunnel
player is created and destroyed without the extractor source
started. In such use case, stopping the source in reset during the
tunnel player destruction leads to failure during assertion check.
Fix: Check for mStarted flag to ensure that stop on source is
called only after they are started.
Change-Id: Ib18e7ee3d10b2cc706944e358046f163d156706c
CRs-Fixed: 440239
Diffstat (limited to 'media/libstagefright/AwesomePlayer.cpp')
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 195 |
1 files changed, 179 insertions, 16 deletions
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 9c0e799..83c480d 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -1,8 +1,6 @@ /* * Copyright (C) 2009 The Android Open Source Project - * Copyright (c) 2012, The Linux Foundation. All rights reserved. - * - * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved. * Not a Contribution, Apache license notifications and license are retained * for attribution purposes only. @@ -68,6 +66,8 @@ #define USE_SURFACE_ALLOC 1 #define FRAME_DROP_FREQ 0 +#define LPA_MIN_DURATION_USEC_ALLOWED 30000000 +#define LPA_MIN_DURATION_USEC_DEFAULT 60000000 namespace android { @@ -607,6 +607,18 @@ void AwesomePlayer::reset_l() { mStats.mVideoHeight = -1; mStats.mFlags = 0; mStats.mTracks.clear(); + mStats.mConsecutiveFramesDropped = 0; + mStats.mCatchupTimeStart = 0; + mStats.mNumTimesSyncLoss = 0; + mStats.mMaxEarlyDelta = 0; + mStats.mMaxLateDelta = 0; + mStats.mMaxTimeSyncLoss = 0; + mStats.mTotalFrames = 0; + mStats.mLastFrameUs = 0; + mStats.mTotalTimeUs = 0; + mStats.mLastPausedTimeMs = 0; + mStats.mLastSeekToTimeMs = 0; + mStats.mFirstFrameLatencyUs = 0; } mWatchForAudioSeekComplete = false; @@ -975,13 +987,21 @@ status_t AwesomePlayer::play_l() { ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0",nchannels); } } - char lpaDecode[128]; + char lpaDecode[PROPERTY_VALUE_MAX]; + uint32_t minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT; + char minUserDefDuration[PROPERTY_VALUE_MAX]; property_get("lpa.decode",lpaDecode,"0"); + property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT"); + minDurationForLPA = atoi(minUserDefDuration); + if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) { + ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec"); + minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT; + } if((strcmp("true",lpaDecode) == 0) && (mAudioPlayer == NULL) && (tunnelObjectsAlive==0) && (nchannels && (nchannels <= 2))) { ALOGV("LPAPlayer::getObjectsAlive() %d",LPAPlayer::objectsAlive); - if ( mDurationUs > 60000000 + if ( mDurationUs > minDurationForLPA && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC)) && LPAPlayer::objectsAlive == 0 && mVideoSource == NULL) { ALOGD("LPAPlayer created, LPA MODE detected mime %s duration %lld", mime, mDurationUs); @@ -1046,6 +1066,12 @@ status_t AwesomePlayer::play_l() { mTimeSource = &mSystemTimeSource; } + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mFirstFrameLatencyStartUs = getTimeOfDayUs(); + mStats.mVeryFirstFrame = true; + } + if (mVideoSource != NULL) { // Kick off video playback postVideoEvent_l(); @@ -1269,6 +1295,11 @@ status_t AwesomePlayer::pause_l(bool at_eos) { Playback::PAUSE, 0); } + if(!(mFlags & AT_EOS)){ + Mutex::Autolock autoLock(mStatsLock); + mStats.mLastPausedTimeMs = mVideoTimeUs/1000; + } + uint32_t params = IMediaPlayerService::kBatteryDataTrackDecoder; if ((mAudioSource != NULL) && (mAudioSource != mAudioTrack)) { params |= IMediaPlayerService::kBatteryDataTrackAudio; @@ -1429,6 +1460,12 @@ status_t AwesomePlayer::seekTo_l(int64_t timeUs) { } mSeeking = SEEK; + + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mFirstFrameLatencyStartUs = getTimeOfDayUs(); + mStats.mVeryFirstFrame = true; + } mSeekNotificationSent = false; mSeekTimeUs = timeUs; modifyFlags((AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS), CLEAR); @@ -1496,7 +1533,12 @@ status_t AwesomePlayer::initAudioDecoder() { CHECK(meta->findCString(kKeyMIMEType, &mime)); #ifdef QCOM_ENHANCED_AUDIO int32_t nchannels = 0; + int32_t isADTS = 0; meta->findInt32( kKeyChannelCount, &nchannels ); + meta->findInt32(kKeyIsADTS, &isADTS); + if(isADTS == 1){ + ALOGV("Widevine content\n"); + } ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0", nchannels); @@ -1510,7 +1552,8 @@ status_t AwesomePlayer::initAudioDecoder() { mime, (TunnelPlayer::mTunnelObjectsAlive), mTunnelAliveAP); if(((strcmp("true",tunnelDecode) == 0)||(atoi(tunnelDecode))) && (TunnelPlayer::mTunnelObjectsAlive == 0) && - mTunnelAliveAP == 0 && + //widevine will fallback to software decoder + mTunnelAliveAP == 0 && (isADTS == 0) && mAudioSink->realtime() && ((!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) || (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) || (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS)) || @@ -1532,6 +1575,12 @@ status_t AwesomePlayer::initAudioDecoder() { else ALOGD("Normal Audio Playback"); #endif + + if (isStreamingHTTP()) { + ALOGV("Streaming, force disable tunnel mode playback"); + mIsTunnelAudio = false; + } + if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) || (mIsTunnelAudio && (mTunnelAliveAP == 0))) { ALOGD("Set Audio Track as Audio Source"); @@ -1549,14 +1598,22 @@ status_t AwesomePlayer::initAudioDecoder() { int64_t durationUs; uint32_t flags = 0; char lpaDecode[128]; + uint32_t minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT; + char minUserDefDuration[PROPERTY_VALUE_MAX]; property_get("lpa.decode",lpaDecode,"0"); + property_get("lpa.min_duration",minUserDefDuration,"LPA_MIN_DURATION_USEC_DEFAULT"); + minDurationForLPA = atoi(minUserDefDuration); + if(minDurationForLPA < LPA_MIN_DURATION_USEC_ALLOWED) { + ALOGE("LPAPlayer::Clip duration setting of less than 30sec not supported, defaulting to 60sec"); + minDurationForLPA = LPA_MIN_DURATION_USEC_DEFAULT; + } if (mAudioTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) { Mutex::Autolock autoLock(mMiscStateLock); if (mDurationUs < 0 || durationUs > mDurationUs) { mDurationUs = durationUs; } } - if ( mDurationUs > 60000000 + if ( mDurationUs > minDurationForLPA && (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG) || !strcasecmp(mime,MEDIA_MIMETYPE_AUDIO_AAC)) && LPAPlayer::objectsAlive == 0 && mVideoSource == NULL && (strcmp("true",lpaDecode) == 0) && (nchannels && (nchannels <= 2)) ) { @@ -1771,6 +1828,12 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) { mDrmManagerClient->setPlaybackStatus(mDecryptHandle, Playback::START, videoTimeUs / 1000); } + + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mLastSeekToTimeMs = mSeekTimeUs/1000; + logFirstFrame(); + } } void AwesomePlayer::onVideoEvent() { @@ -1783,6 +1846,14 @@ void AwesomePlayer::onVideoEvent() { } mVideoEventPending = false; + { + Mutex::Autolock autoLock(mStatsLock); + if(!mStats.mVeryFirstFrame && mSeeking == NO_SEEK){ + mStats.mTotalTimeUs += getTimeOfDayUs() - mStats.mLastFrameUs; + } + mStats.mLastFrameUs = getTimeOfDayUs(); + } + if (mSeeking != NO_SEEK) { if (mVideoBuffer) { mVideoBuffer->release(); @@ -1916,18 +1987,26 @@ void AwesomePlayer::onVideoEvent() { modifyFlags(FIRST_FRAME, CLEAR); mSinceLastDropped = 0; mTimeSourceDeltaUs = ts->getRealTimeUs() - timeUs; + + { + Mutex::Autolock autoLock(mStatsLock); + if(mStats.mVeryFirstFrame){ + logFirstFrame(); + mStats.mLastFrameUs = getTimeOfDayUs(); + } + } } - int64_t realTimeUs, mediaTimeUs; + int64_t realTimeUs, mediaTimeUs, nowUs = 0, latenessUs = 0; if (!(mFlags & AUDIO_AT_EOS) && mAudioPlayer != NULL && mAudioPlayer->getMediaTimeMapping(&realTimeUs, &mediaTimeUs)) { mTimeSourceDeltaUs = realTimeUs - mediaTimeUs; } if (wasSeeking == SEEK_VIDEO_ONLY) { - int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; + nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; - int64_t latenessUs = nowUs - timeUs; + latenessUs = nowUs - timeUs; ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); @@ -1939,9 +2018,9 @@ void AwesomePlayer::onVideoEvent() { if (wasSeeking == NO_SEEK) { // Let's display the first frame after seeking right away. - int64_t nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; + nowUs = ts->getRealTimeUs() - mTimeSourceDeltaUs; - int64_t latenessUs = nowUs - timeUs; + latenessUs = nowUs - timeUs; ATRACE_INT("Video Lateness (ms)", latenessUs / 1E3); @@ -1988,6 +2067,11 @@ void AwesomePlayer::onVideoEvent() { { Mutex::Autolock autoLock(mStatsLock); ++mStats.mNumVideoFramesDropped; + mStats.mConsecutiveFramesDropped++; + if (mStats.mConsecutiveFramesDropped == 1){ + mStats.mCatchupTimeStart = mTimeSource->getRealTimeUs(); + } + if(!(mFlags & AT_EOS)) logLate(timeUs,nowUs,latenessUs); } postVideoEvent_l(); @@ -1997,6 +2081,11 @@ void AwesomePlayer::onVideoEvent() { if (latenessUs < -10000) { // We're more than 10ms early. + logOnTime(timeUs,nowUs,latenessUs); + { + Mutex::Autolock autoLock(mStatsLock); + mStats.mConsecutiveFramesDropped = 0; + } postVideoEvent_l(10000); return; } @@ -2017,6 +2106,12 @@ void AwesomePlayer::onVideoEvent() { notifyListener_l(MEDIA_INFO, MEDIA_INFO_RENDERING_START); } + { + Mutex::Autolock autoLock(mStatsLock); + logOnTime(timeUs,nowUs,latenessUs); + mStats.mTotalFrames++; + mStats.mConsecutiveFramesDropped = 0; + } } mVideoBuffer->release(); @@ -2814,13 +2909,37 @@ status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const { if ((ssize_t)i == mStats.mVideoTrackIndex) { fprintf(out, - " videoDimensions(%d x %d), " - "numVideoFramesDecoded(%lld), " - "numVideoFramesDropped(%lld)\n", + " videoDimensions(%d x %d)\n" + " Total Video Frames Decoded(%lld)\n" + " Total Video Frames Rendered(%lld)\n" + " Total Playback Duration(%lld ms)\n" + " numVideoFramesDropped(%lld)\n" + " Average Frames Per Second(%.4f)\n" + " Last Seek To Time(%lld ms)\n" + " Last Paused Time(%lld ms)\n" + " First Frame Latency (%lld ms)\n" + " Number of times AV Sync Lost(%u)\n" + " Max Video Ahead Time Delta(%u)\n" + " Max Video Behind Time Delta(%u)\n" + " Max Time Sync Loss(%u)\n" + " EOS(%d)\n" + " PLAYING(%d)\n", mStats.mVideoWidth, mStats.mVideoHeight, mStats.mNumVideoFramesDecoded, - mStats.mNumVideoFramesDropped); + mStats.mTotalFrames, + mStats.mTotalTimeUs/1000, + mStats.mNumVideoFramesDropped, + ((double)(mStats.mTotalFrames)*1E6)/((double)mStats.mTotalTimeUs), + mStats.mLastSeekToTimeMs, + mStats.mLastPausedTimeMs, + mStats.mFirstFrameLatencyUs/1000, + mStats.mNumTimesSyncLoss, + -mStats.mMaxEarlyDelta/1000, + mStats.mMaxLateDelta/1000, + mStats.mMaxTimeSyncLoss/1000, + (mFlags & AT_EOS) > 0, + (mFlags & PLAYING) > 0); } } @@ -2854,4 +2973,48 @@ void AwesomePlayer::modifyFlags(unsigned value, FlagMode mode) { } } +inline void AwesomePlayer::logFirstFrame() { + mStats.mFirstFrameLatencyUs = getTimeOfDayUs()-mStats.mFirstFrameLatencyStartUs; + mStats.mVeryFirstFrame = false; +} + +inline void AwesomePlayer::logCatchUp(int64_t ts, int64_t clock, int64_t delta) +{ + if (mStats.mConsecutiveFramesDropped > 0) { + mStats.mNumTimesSyncLoss++; + if (mStats.mMaxTimeSyncLoss < (clock - mStats.mCatchupTimeStart) && clock > 0 && ts > 0) { + mStats.mMaxTimeSyncLoss = clock - mStats.mCatchupTimeStart; + } + } +} + +inline void AwesomePlayer::logLate(int64_t ts, int64_t clock, int64_t delta) +{ + if (mStats.mMaxLateDelta < delta && clock > 0 && ts > 0) { + mStats.mMaxLateDelta = delta; + } +} + +inline void AwesomePlayer::logOnTime(int64_t ts, int64_t clock, int64_t delta) +{ + bool needLogLate = false; + logCatchUp(ts, clock, delta); + if (delta <= 0) { + if ((-delta) > (-mStats.mMaxEarlyDelta) && clock > 0 && ts > 0) { + mStats.mMaxEarlyDelta = delta; + } + } + else { + needLogLate = true; + } + + if(needLogLate) logLate(ts, clock, delta); +} + +inline int64_t AwesomePlayer::getTimeOfDayUs() { + struct timeval tv; + gettimeofday(&tv, NULL); + + return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; +} } // namespace android |