summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--media/libstagefright/AwesomePlayer.cpp195
-rw-r--r--media/libstagefright/QCMediaDefs.cpp4
-rw-r--r--media/libstagefright/TunnelPlayer.cpp174
-rw-r--r--media/libstagefright/include/AwesomePlayer.h22
-rw-r--r--services/audioflinger/AudioFlinger.cpp3
5 files changed, 351 insertions, 47 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
diff --git a/media/libstagefright/QCMediaDefs.cpp b/media/libstagefright/QCMediaDefs.cpp
index ec2d04e..5e8b84f 100644
--- a/media/libstagefright/QCMediaDefs.cpp
+++ b/media/libstagefright/QCMediaDefs.cpp
@@ -1,4 +1,4 @@
-/*Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/*Copyright (c) 2012 - 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -50,6 +50,6 @@ const char *MEDIA_MIMETYPE_AUDIO_DTS = "audio/dts";
const char *MEDIA_MIMETYPE_AUDIO_DTS_LBR = "audio/dts-lbr";
const char *MEDIA_MIMETYPE_AUDIO_EAC3 = "audio/eac3";
const char *MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS = "audio/amr-wb-plus";
-
+const char *MEDIA_MIMETYPE_CONTAINER_QCMPEG2TS = "video/qc-mp2ts";
} // namespace android
diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp
index fa2dc06..475cf56 100644
--- a/media/libstagefright/TunnelPlayer.cpp
+++ b/media/libstagefright/TunnelPlayer.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
* Not a Contribution, Apache license notifications and license are retained
* for attribution purposes only.
*
@@ -50,8 +50,10 @@
static const char mName[] = "TunnelPlayer";
#define MEM_METADATA_SIZE 64
-#define MEM_BUFFER_SIZE (600*1024 - MEM_METADATA_SIZE)
+#define MEM_PADDING 64
+#define MEM_BUFFER_SIZE (256*1024 - MEM_METADATA_SIZE)
#define MEM_BUFFER_COUNT 4
+#define TUNNEL_BUFFER_TIME 1500000
namespace android {
int TunnelPlayer::mTunnelObjectsAlive = 0;
@@ -100,6 +102,7 @@ mObserver(observer) {
//mAudioFlinger->registerClient(mAudioFlingerClient);
mSeekTimeUs = 0;
+ mIsAudioRouted = false;
mHasVideo = hasVideo;
initCheck = true;
@@ -265,7 +268,7 @@ status_t TunnelPlayer::start(bool sourceAlreadyStarted) {
CHECK(!mStarted);
CHECK(mSource != NULL);
- ALOGD("start: sourceAlreadyStarted %d", sourceAlreadyStarted);
+ ALOGV("start: sourceAlreadyStarted %d", sourceAlreadyStarted);
//Check if the source is started, start it
status_t err;
if (!sourceAlreadyStarted) {
@@ -363,7 +366,7 @@ status_t TunnelPlayer::start(bool sourceAlreadyStarted) {
mIsAudioRouted = true;
mStarted = true;
mAudioSink->start();
- ALOGV("Waking up decoder thread");
+ ALOGV("Waking up extractor thread");
pthread_cond_signal(&extractor_cv);
return OK;
@@ -372,16 +375,44 @@ status_t TunnelPlayer::start(bool sourceAlreadyStarted) {
status_t TunnelPlayer::seekTo(int64_t time_us) {
ALOGV("seekTo: time_us %lld", time_us);
- if ( mReachedEOS ) {
- mReachedEOS = false;
- mReachedOutputEOS = false;
+
+ if (mPositionTimeRealUs != 0) {
+ //check for return conditions only if seektime
+ // is set
+ if (time_us > mPositionTimeRealUs){
+ if((time_us - mPositionTimeRealUs) < TUNNEL_BUFFER_TIME){
+ ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
+ mObserver->postAudioSeekComplete();
+ return OK;
+ }
+ } else {
+ if((mPositionTimeRealUs - time_us) < TUNNEL_BUFFER_TIME){
+ ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs);
+ mObserver->postAudioSeekComplete();
+ return OK;
+ }
+ }
}
+
mSeeking = true;
mSeekTimeUs = time_us;
+ mPauseTime = mSeekTimeUs;
ALOGV("In seekTo(), mSeekTimeUs %lld",mSeekTimeUs);
- mAudioSink->flush();
- pthread_cond_signal(&extractor_cv);
- //TODO: Update the mPauseTime
+
+ if (mIsAudioRouted) {
+ mAudioSink->flush();
+ }
+
+ if (mReachedEOS) {
+ mReachedEOS = false;
+ mReachedOutputEOS = false;
+ if(mPaused == false) {
+ ALOGV("Going to signal extractor thread since playback is already going on ");
+ pthread_cond_signal(&extractor_cv);
+ ALOGV("Signalled extractor thread.");
+ }
+ }
+ ALOGV("seek done.");
return OK;
}
void TunnelPlayer::pause(bool playPendingSamples) {
@@ -407,6 +438,7 @@ void TunnelPlayer::pause(bool playPendingSamples) {
}
void TunnelPlayer::resume() {
+ Mutex::Autolock autoLock(mLock);
ALOGV("resume: mPaused %d",mPaused);
if ( mPaused) {
CHECK(mStarted);
@@ -435,8 +467,11 @@ void TunnelPlayer::resume() {
mIsAudioRouted = true;
}
mPaused = false;
+ ALOGV("Audio sink open succeeded.");
mAudioSink->start();
+ ALOGV("Audio sink start succeeded.");
pthread_cond_signal(&extractor_cv);
+ ALOGV("Audio signalling extractor thread.");
}
}
@@ -446,15 +481,20 @@ size_t TunnelPlayer::AudioSinkCallback(
void *buffer, size_t size, void *cookie) {
if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) {
TunnelPlayer *me = (TunnelPlayer *)cookie;
- me->mReachedEOS = true;
- me->mReachedOutputEOS = true;
- ALOGV("postAudioEOS");
- me->mObserver->postAudioEOS(0);
+ if(me->mReachedEOS == true) {
+ //in the case of seek all these flags will be reset
+ me->mReachedOutputEOS = true;
+ ALOGV("postAudioEOS mSeeking %d", me->mSeeking);
+ me->mObserver->postAudioEOS(0);
+ }else {
+ ALOGV("postAudioEOS ignored since %d", me->mSeeking);
+ }
}
return 1;
}
void TunnelPlayer::reset() {
+ ALOGV("Reset");
mReachedEOS = true;
@@ -482,7 +522,8 @@ void TunnelPlayer::reset() {
mInputBuffer = NULL;
}
- mSource->stop();
+ if(mStarted)
+ mSource->stop();
// The following hack is necessary to ensure that the OMX
// component is completely released by the time we may try
@@ -529,7 +570,7 @@ void TunnelPlayer::extractorThreadEntry() {
pid_t tid = gettid();
androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
- prctl(PR_SET_NAME, (unsigned long)"Tunnel DecodeThread", 0, 0, 0);
+ prctl(PR_SET_NAME, (unsigned long)"Extractor Thread", 0, 0, 0);
ALOGV("extractorThreadEntry wait for signal \n");
if (!mStarted) {
@@ -545,26 +586,79 @@ void TunnelPlayer::extractorThreadEntry() {
const char *mime;
bool success = format->findCString(kKeyMIMEType, &mime);
}
- void* local_buf = malloc(BufferSizeToUse);
+ void* local_buf = malloc(BufferSizeToUse + MEM_PADDING);
+ int *lptr = ((int*)local_buf);
int bytesWritten = 0;
+ bool lSeeking = false;
+ bool lPaused = false;
while (!killExtractorThread) {
if (mReachedEOS || mPaused || !mIsAudioRouted) {
+ ALOGV("Going to sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
pthread_mutex_lock(&extractor_mutex);
pthread_cond_wait(&extractor_cv, &extractor_mutex);
pthread_mutex_unlock(&extractor_mutex);
+ ALOGV("Woke up from sleep before write since "
+ "mReachedEOS %d, mPaused %d, mIsAudioRouted %d",
+ mReachedEOS, mPaused, mIsAudioRouted);
continue;
}
if (!mIsA2DPEnabled) {
- ALOGW("FillBuffer: MemBuffer size %d", BufferSizeToUse);
+ ALOGV("FillBuffer: MemBuffer size %d", BufferSizeToUse);
ALOGV("Fillbuffer started");
bytesWritten = fillBuffer(local_buf, BufferSizeToUse);
ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten);
if(!killExtractorThread) {
- mAudioSink->write(local_buf, bytesWritten);
- if(mReachedEOS && bytesWritten)
- mAudioSink->write(local_buf, 0);
+ mLock.lock();
+ lPaused = mPaused;
+ mLock.unlock();
+
+ if(lPaused == true) {
+ //write only if player is not in paused state. Sleep on lock
+ // resume is called
+ ALOGV("Going to sleep in decodethreadiwrite since sink is paused");
+ pthread_mutex_lock(&extractor_mutex);
+ pthread_cond_wait(&extractor_cv, &extractor_mutex);
+ ALOGV("Going to unlock n decodethreadwrite since sink "
+ "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d",
+ mPaused, mIsAudioRouted, mReachedEOS);
+ pthread_mutex_unlock(&extractor_mutex);
+ }
+ mLock.lock();
+ lSeeking = mSeeking||mInternalSeeking;
+ mLock.unlock();
+
+ if(lSeeking == false && (killExtractorThread == false)){
+ //if we are seeking, ignore write, otherwise write
+ ALOGV("Fillbuffer before write %d and seek flag %d", mSeeking,
+ lptr[MEM_BUFFER_SIZE/sizeof(int)]);
+ int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten);
+ ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking);
+ if(lWrittenBytes > 0) {
+ //send EOS only if write was successful, if is_buffer_available
+ // is flushed out (which returns 0 do not SEND EOS
+ ALOGV("Fillbuffer after write and seek flag %d", mSeeking);
+ mLock.lock();
+ lSeeking = mSeeking||mInternalSeeking;
+ mLock.unlock();
+ //ignore posting zero length buffer is seeking is set
+ if(mReachedEOS && bytesWritten && !lSeeking && (killExtractorThread == false)) {
+ ALOGV("Fillbuffer after write sent EOS flag %d", lSeeking);
+ mAudioSink->write(local_buf, 0);
+ } else {
+ ALOGV("Not sending EOS buffer sent since seeking %d, "
+ "kill %d and mReachedEOS %d", \
+ lSeeking, killExtractorThread, mReachedEOS);
+ }
+ } else {
+ ALOGV("write exited because of flush %d", mSeeking);
+ }
+ } else {
+ ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking);
+ }
}
}
}
@@ -588,7 +682,7 @@ void TunnelPlayer::createThreads() {
extractorThreadAlive = true;
- ALOGV("Creating decoder Thread");
+ ALOGV("Creating Extractor Thread");
pthread_create(&extractorThread, &attr, extractorThreadWrapper, this);
pthread_attr_destroy(&attr);
@@ -603,6 +697,10 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {
size_t size_done = 0;
size_t size_remaining = size;
+ int *ldataptr = (int*) data;
+ //clear the flag since we dont know whether we are seeking or not, yet
+ ldataptr[(MEM_BUFFER_SIZE/sizeof(int))] = 0;
+ ALOGV("fillBuffer: Clearing seek flag in fill buffer");
while (size_remaining > 0) {
MediaSource::ReadOptions options;
@@ -635,10 +733,13 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) {
mSeeking = false;
if (mObserver && !mInternalSeeking) {
- ALOGD("fillBuffer: Posting audio seek complete event");
+ ALOGV("fillBuffer: Posting audio seek complete event");
postSeekComplete = true;
}
mInternalSeeking = false;
+ ALOGV("fillBuffer: Setting seek flag in fill buffer");
+ //set the flag since we know that this buffer is the new positions buffer
+ ldataptr[(MEM_BUFFER_SIZE/sizeof(int))] = 1;
}
}
if (mInputBuffer == NULL) {
@@ -708,6 +809,7 @@ int64_t TunnelPlayer::getRealTimeUs() {
}
void TunnelPlayer::getPlayedTimeFromDSP_l(int64_t* timeStamp ) {
+ ALOGV("going to query timestamp");
mAudioSink->getTimeStamp((uint64_t*)timeStamp);
ALOGV("timestamp returned from DSP %lld ", (*timeStamp));
return;
@@ -744,15 +846,25 @@ void TunnelPlayer::requestAndWaitForExtractorThreadExit() {
if (!extractorThreadAlive)
return;
- if (mIsAudioRouted)
- mAudioSink->flush();
+
killExtractorThread = true;
+
+ ALOGV("requestAndWaitForExtractorThreadExit +0");
+ if (mIsAudioRouted && !mReachedOutputEOS) {
+ mAudioSink->flush();
+ }
+
+ ALOGV("requestAndWaitForExtractorThreadExit +1");
pthread_cond_signal(&extractor_cv);
+ ALOGV("requestAndWaitForExtractorThreadExit +2");
pthread_join(extractorThread,NULL);
- ALOGD("Extractor thread killed");
+ ALOGV("requestAndWaitForExtractorThreadExit +3");
+
+ ALOGV("Extractor thread killed");
}
void TunnelPlayer::onPauseTimeOut() {
+ Mutex::Autolock autoLock(mLock);
int64_t playedTime = 0;
ALOGV("onPauseTimeOut");
if (!mPauseEventPending) {
@@ -765,17 +877,23 @@ void TunnelPlayer::onPauseTimeOut() {
mReachedOutputEOS = false;
if(mSeeking == false) {
+ ALOGV("onPauseTimeOut +2");
mInternalSeeking = true;
- mLock.lock();
+ ALOGV("onPauseTimeOut +3");
getPlayedTimeFromDSP_l(&playedTime);
- mLock.unlock();
mSeekTimeUs += playedTime;
} else {
ALOGV("Do not update seek time if it was seeked before onpause timeout");
}
// 2.) Close routing Session
+ ALOGV("onPauseTimeOut +4");
+ mAudioSink->flush();
+ ALOGV("onPauseTimeOut +5");
+ mAudioSink->stop();
+ ALOGV("onPauseTimeOut +6");
mAudioSink->close();
+ ALOGV("onPauseTimeOut +7");
mIsAudioRouted = false;
// 3.) Release Wake Lock
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 107c5da..a5586dd 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -303,6 +304,12 @@ private:
ASSIGN
};
void modifyFlags(unsigned value, FlagMode mode);
+ void logFirstFrame();
+ void logCatchUp(int64_t ts, int64_t clock, int64_t delta);
+ void logLate(int64_t ts, int64_t clock, int64_t delta);
+ void logOnTime(int64_t ts, int64_t clock, int64_t delta);
+ int64_t getTimeOfDayUs();
+ bool mStatistics;
struct TrackStat {
String8 mMIME;
@@ -328,6 +335,21 @@ private:
int32_t mVideoHeight;
uint32_t mFlags;
Vector<TrackStat> mTracks;
+
+ int64_t mConsecutiveFramesDropped;
+ uint32_t mCatchupTimeStart;
+ uint32_t mNumTimesSyncLoss;
+ uint32_t mMaxEarlyDelta;
+ uint32_t mMaxLateDelta;
+ uint32_t mMaxTimeSyncLoss;
+ uint64_t mTotalFrames;
+ int64_t mFirstFrameLatencyStartUs; //first frame latency start
+ int64_t mFirstFrameLatencyUs;
+ int64_t mLastFrameUs;
+ bool mVeryFirstFrame;
+ int64_t mTotalTimeUs;
+ int64_t mLastPausedTimeMs;
+ int64_t mLastSeekToTimeMs;
} mStats;
status_t setVideoScalingMode(int32_t mode);
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 724b1e3..12cfe9d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -6166,12 +6166,13 @@ AudioFlinger::DirectAudioTrack::~DirectAudioTrack() {
mAudioFlinger->deleteEffectSession();
deallocateBufPool();
}
+ AudioSystem::releaseOutput(mOutput);
releaseWakeLock();
+
if (mPowerManager != 0) {
sp<IBinder> binder = mPowerManager->asBinder();
binder->unlinkToDeath(mDeathRecipient);
}
- AudioSystem::releaseOutput(mOutput);
}
status_t AudioFlinger::DirectAudioTrack::start() {