summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/AwesomePlayer.cpp
diff options
context:
space:
mode:
authorAlexy Joseph <alexyj@codeaurora.org>2012-12-22 00:58:48 -0800
committerGerrit Code Review <gerrit@review.cyanogenmod.com>2013-01-26 19:49:25 -0800
commitd7a251d1422895694f71764678ff48d021224752 (patch)
tree80205dc0b9aece93abd5e8ba25d0e2a5464606f5 /media/libstagefright/AwesomePlayer.cpp
parent391bf29ad1177d973cb6a9daea13677373204176 (diff)
downloadframeworks_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.cpp195
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