From 9be07ef6a1d4dc591a25b3364a6ca0ad6f524ab9 Mon Sep 17 00:00:00 2001 From: Haynes Mathew George Date: Fri, 1 Feb 2013 18:49:00 -0800 Subject: libstagefright: Squashed commit of LPA/tunnel updates from CAF libstagefright: Exceptions in using Tunnel mode decode - Accumulate all known exceptions to a separate function Change-Id: I61bbc288c9a087559db210e76141b8c57e67fff0 CRs-Fixed: 432080 libstagefright : Stability fixes for Tunnel Player (part 2) - Synchronize b/w reset() and onPauseTimeout - Synchronize b/w seekTo() and onPauseTimeout Change-Id: Ia5cfc6b4dcc326ead440fba35d809d4f3f1b5a81 CRs-Fixed: 449122 Revert "Revert "libstagefright: Convert mono to stereo for LPA clips"" This reverts commit 0db8a19fb3216a8a83d5d6cbd5f1ccbf997a20d8. libstagefright: Port Tunnel mode fixes to LPA - Miscellaneous fixes for seek, pause/resume, EOS handling - Miscellaneous fixes for synchronization between the decoder thread, TimedEventQueue and the player thread. - This change is a port of a similar set of changes made for TunnelPlayer Change-Id: I82c2904f7aedfb9c4f03200419fcba8b038e3d54 libstagefright: Avoid use of extra bytes to signal seek processed - A few bytes were reserved in the buffer sent by Tunnel/LPA player to audio HAL to indicate a seek has been processed and there is no need to skip it. - We won't need this method anymore as this can be fixed instead by synchronizing seekTo() and the extractor/decoder threads. Change-Id: Ic02ae1699bb59e2f6b8d9fb599d0fa43fd3f19e3 libstagefright: LPAPlayer synchronization fixes - synchronize b/w seekTo() and onPauseTimeout() - synchronize b/w reset() and onPauseTimeout() Change-Id: I29a4ccf02e28fe7b7c00e35a679ff2b5271ffb6f libstagefright: TunnelPlayer performance tweaks Some tweaks when TunnelPlayer is used for audio/video playback - Keep the extractor thread at ANDROID_PRIORITY_NORMAL - sched_yield() after reading a frame to give the video thread(s) (CallbackDispatcher and/or TimedEventQueue) to be scheduled Change-Id: If0d86d629fd0e15aff917af8589472578cd28bf4 CRs-Fixed: 444041 --- include/media/stagefright/LPAPlayer.h | 5 + media/libstagefright/AwesomePlayer.cpp | 53 +++++- media/libstagefright/LPAPlayerALSA.cpp | 267 +++++++++++++++++++-------- media/libstagefright/TunnelPlayer.cpp | 59 ++++-- media/libstagefright/include/AwesomePlayer.h | 3 + 5 files changed, 289 insertions(+), 98 deletions(-) diff --git a/include/media/stagefright/LPAPlayer.h b/include/media/stagefright/LPAPlayer.h index b0e1d31..91f9b3a 100755 --- a/include/media/stagefright/LPAPlayer.h +++ b/include/media/stagefright/LPAPlayer.h @@ -93,6 +93,8 @@ private: bool mA2DPEnabled; int32_t mChannelMask; int32_t numChannels; + int32_t mNumOutputChannels; + int32_t mNumInputChannels; int32_t mSampleRate; int64_t mLatencyUs; size_t mFrameSize; @@ -258,6 +260,9 @@ private: MediaPlayerBase::AudioSink *audioSink, void *buffer, size_t size, void *cookie); size_t AudioCallback(void *cookie, void *data, size_t size); + int64_t getMediaTimeUs_l(); + + void convertMonoToStereo(int16_t *data, size_t size); LPAPlayer(const LPAPlayer &); LPAPlayer &operator=(const LPAPlayer &); diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 6dc18f8..6c1f4c5 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -1537,9 +1537,10 @@ status_t AwesomePlayer::initAudioDecoder() { int32_t isADTS = 0; meta->findInt32( kKeyChannelCount, &nchannels ); meta->findInt32(kKeyIsADTS, &isADTS); - if(isADTS == 1){ + if (isADTS == 1) { ALOGV("Widevine content\n"); } + ALOGV("nchannels %d;LPA will be skipped if nchannels is > 2 or nchannels == 0", nchannels); #endif @@ -1555,7 +1556,7 @@ status_t AwesomePlayer::initAudioDecoder() { //widevine will fallback to software decoder if (sys_prop_enabled && (TunnelPlayer::mTunnelObjectsAlive == 0) && - mTunnelAliveAP == 0 && (isADTS == 0) && + (mTunnelAliveAP == 0) && (isADTS == 0) && mAudioSink->realtime() && inSupportedTunnelFormats(mime)) { @@ -1576,10 +1577,7 @@ status_t AwesomePlayer::initAudioDecoder() { else ALOGD("Normal Audio Playback"); - if (isStreamingHTTP()) { - ALOGV("Streaming, force disable tunnel mode playback"); - mIsTunnelAudio = false; - } + checkTunnelExceptions(); if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW) || (mIsTunnelAudio && (mTunnelAliveAP == 0))) { @@ -2050,8 +2048,8 @@ void AwesomePlayer::onVideoEvent() { if (latenessUs > 40000) { // We're more than 40ms late. - ALOGV("we're late by %lld us (%.2f secs)", - latenessUs, latenessUs / 1E6); + ALOGE("we're late by %lld us nowUs %lld, timeUs %lld", + latenessUs, nowUs, timeUs); if (!(mFlags & SLOW_DECODER_HACK) || mSinceLastDropped > FRAME_DROP_FREQ) @@ -3056,6 +3054,45 @@ bool AwesomePlayer::inSupportedTunnelFormats(const char * mime) { ALOGW("Tunnel playback unsupported for %s", mime); return false; } + +void AwesomePlayer::checkTunnelExceptions() +{ + /* exception 1: No streaming */ + if (isStreamingHTTP()) { + ALOGV("Streaming, force disable tunnel mode playback"); + mIsTunnelAudio = false; + return; + } + + /* below exceptions are only for av content */ + if (mVideoTrack == NULL) return; + + /* exception 2: No avi having video + mp3 */ + if (mExtractor == NULL) return; + + sp metaData = mExtractor->getMetaData(); + const char * container; + + /*only proceed for avi content.*/ + if (!metaData->findCString(kKeyMIMEType, &container) || + strcmp(container, MEDIA_MIMETYPE_CONTAINER_AVI)) { + return; + } + + CHECK(mAudioTrack != NULL); + + const char * mime; + metaData = mAudioTrack->getFormat(); + /*disable for av content having mp3*/ + if (metaData->findCString(kKeyMIMEType, &mime) && + !strcmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) { + ALOGV("Clip has AVI extractor and mp3 content, disable tunnel mode"); + mIsTunnelAudio = false; + return; + } + + return; +} #endif } // namespace android diff --git a/media/libstagefright/LPAPlayerALSA.cpp b/media/libstagefright/LPAPlayerALSA.cpp index 38d6bac..56746d0 100644 --- a/media/libstagefright/LPAPlayerALSA.cpp +++ b/media/libstagefright/LPAPlayerALSA.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. * @@ -51,11 +51,14 @@ static const char mName[] = "LPAPlayer"; -#define MEM_BUFFER_SIZE 262144 +#define MEM_PADDING 64 +#define MEM_BUFFER_SIZE (256*1024) #define MEM_BUFFER_COUNT 4 #define PCM_FORMAT 2 #define NUM_FDS 2 +#define LPA_BUFFER_TIME 1500000 + namespace android { int LPAPlayer::objectsAlive = 0; @@ -87,7 +90,8 @@ mAudioSink(audioSink), mObserver(observer) { ALOGV("LPAPlayer::LPAPlayer() ctor"); objectsAlive++; - numChannels =0; + mNumOutputChannels =0; + mNumInputChannels = 0; mPaused = false; mIsA2DPEnabled = false; mAudioFlinger = NULL; @@ -256,20 +260,24 @@ status_t LPAPlayer::start(bool sourceAlreadyStarted) { success = format->findInt32(kKeySampleRate, &mSampleRate); CHECK(success); - success = format->findInt32(kKeyChannelCount, &numChannels); + success = format->findInt32(kKeyChannelCount, &mNumInputChannels); CHECK(success); + // Always produce stereo output + mNumOutputChannels = 2; + if(!format->findInt32(kKeyChannelMask, &mChannelMask)) { // log only when there's a risk of ambiguity of channel mask selection - ALOGI_IF(numChannels > 2, - "source format didn't specify channel mask, using (%d) channel order", numChannels); + ALOGI_IF(mNumInputChannels > 2, + "source format didn't specify channel mask, using (%d) channel order", mNumInputChannels); mChannelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; } audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_DIRECT); - ALOGV("mAudiosink->open() mSampleRate %d, numChannels %d, mChannelMask %d, flags %d",mSampleRate, numChannels, mChannelMask, flags); + ALOGV("mAudiosink->open() mSampleRate %d, numOutputChannels %d, mChannelMask %d, flags %d",mSampleRate, + mNumOutputChannels, mChannelMask, flags); err = mAudioSink->open( - mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT, + mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, &LPAPlayer::AudioSinkCallback, this, @@ -301,16 +309,40 @@ status_t LPAPlayer::start(bool sourceAlreadyStarted) { status_t LPAPlayer::seekTo(int64_t time_us) { Mutex::Autolock autoLock(mLock); ALOGV("seekTo: time_us %lld", time_us); - if ( mReachedEOS ) { - mReachedEOS = false; - mReachedOutputEOS = false; + + int64_t mediaTimeUs = getMediaTimeUs_l(); + + if (mediaTimeUs != 0) { + //check for return conditions only if seektime + // is set + int64_t diffUs = time_us - mediaTimeUs; + + if (labs(diffUs) < LPA_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(&decoder_cv); + + if (mIsAudioRouted) { + mAudioSink->flush(); + } + + if (mReachedEOS) { + mReachedEOS = false; + mReachedOutputEOS = false; + if(mPaused == false) { + ALOGV("Going to signal decoder thread since playback is already going on "); + pthread_cond_signal(&decoder_cv); + ALOGV("Signalled extractor thread."); + } + } + ALOGV("seek done."); return OK; } @@ -322,41 +354,26 @@ void LPAPlayer::pause(bool playPendingSamples) { ALOGV("pause: playPendingSamples %d", playPendingSamples); mPaused = true; A2DPState state; - if (playPendingSamples) { - if (!mIsA2DPEnabled) { - if (!mPauseEventPending) { - ALOGV("Posting an event for Pause timeout"); - mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC); - mPauseEventPending = true; - } - mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED); - } - else { - mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED); - } - if (mAudioSink.get() != NULL) - mAudioSink->pause(); + if (!mIsA2DPEnabled) { + if (!mPauseEventPending) { + ALOGV("Posting an event for Pause timeout"); + mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC); + mPauseEventPending = true; + } + mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED); } else { - if (!mIsA2DPEnabled) { - if(!mPauseEventPending) { - ALOGV("Posting an event for Pause timeout"); - mQueue.postEventWithDelay(mPauseEvent, LPA_PAUSE_TIMEOUT_USEC); - mPauseEventPending = true; - } - mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_DISABLED); - } else { - mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED); - } - if (mAudioSink.get() != NULL) { - ALOGV("AudioSink pause"); - mAudioSink->pause(); - } + mPauseTime = mSeekTimeUs + getTimeStamp(A2DP_ENABLED); + } + + if (mAudioSink.get() != NULL) { + ALOGV("AudioSink pause"); + mAudioSink->pause(); } } void LPAPlayer::resume() { ALOGV("resume: mPaused %d",mPaused); - Mutex::Autolock autoLock(mResumeLock); + Mutex::Autolock autoLock(mLock); if ( mPaused) { CHECK(mStarted); if (!mIsA2DPEnabled) { @@ -372,7 +389,7 @@ void LPAPlayer::resume() { audio_output_flags_t flags = (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_LPA | AUDIO_OUTPUT_FLAG_DIRECT); status_t err = mAudioSink->open( - mSampleRate, numChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT, + mSampleRate, mNumOutputChannels, mChannelMask, AUDIO_FORMAT_PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, &LPAPlayer::AudioSinkCallback, this, @@ -394,30 +411,42 @@ size_t LPAPlayer::AudioSinkCallback( void *buffer, size_t size, void *cookie) { if (buffer == NULL && size == AudioTrack::EVENT_UNDERRUN) { LPAPlayer *me = (LPAPlayer *)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 LPAPlayer::reset() { + ALOGD("Reset"); + + Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout + + //cancel any pending onpause timeout events + //doesnt matter if the event is really present or not + mPauseEventPending = false; + mQueue.cancelEvent(mPauseEvent->eventID()); - ALOGV("Reset"); // Close the audiosink after all the threads exited to make sure mReachedEOS = true; // make sure Decoder thread has exited - ALOGV("Closing all the threads"); + ALOGD("Closing all the threads"); requestAndWaitForDecoderThreadExit(); requestAndWaitForA2DPNotificationThreadExit(); - ALOGV("Close the Sink"); + ALOGD("Close the Sink"); if (mIsAudioRouted) { mAudioSink->stop(); mAudioSink->close(); mAudioSink.clear(); + mIsAudioRouted = false; } // Make sure to release any buffer we hold onto so that the // source is able to stop(). @@ -490,25 +519,80 @@ void LPAPlayer::decoderThreadEntry() { return; } void* local_buf = malloc(MEM_BUFFER_SIZE); + if(local_buf == (void*) NULL) { + killDecoderThread = true; + ALOGE("Malloc failed"); + return; + } + int *lptr = ((int*)local_buf); int bytesWritten = 0; + + if (!local_buf) { + ALOGE("Failed to allocate temporary buffer for decoderThread"); + return; + } + + bool lSeeking = false; + bool lPaused = false; + while (!killDecoderThread) { if (mReachedEOS || mPaused || !mIsAudioRouted) { + ALOGV("Going to sleep before write since " + "mReachedEOS %d, mPaused %d, mIsAudioRouted %d", + mReachedEOS, mPaused, mIsAudioRouted); pthread_mutex_lock(&decoder_mutex); pthread_cond_wait(&decoder_cv, &decoder_mutex); pthread_mutex_unlock(&decoder_mutex); + ALOGV("Woke up from sleep before write since " + "mReachedEOS %d, mPaused %d, mIsAudioRouted %d", + mReachedEOS, mPaused, mIsAudioRouted); continue; } if (!mIsA2DPEnabled) { ALOGV("FillBuffer: MemBuffer size %d", MEM_BUFFER_SIZE); ALOGV("Fillbuffer started"); - //TODO: Add memset - bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE); - ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten); + if (mNumInputChannels == 1) { + bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE/2); + CHECK(bytesWritten <= MEM_BUFFER_SIZE/2); + + convertMonoToStereo((int16_t*)local_buf, bytesWritten); + bytesWritten *= 2; + } else { + bytesWritten = fillBuffer(local_buf, MEM_BUFFER_SIZE); + CHECK(bytesWritten <= MEM_BUFFER_SIZE); + } + ALOGV("FillBuffer completed bytesToWrite %d", bytesWritten); if(!killDecoderThread) { - mAudioSink->write(local_buf, bytesWritten); + 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(&decoder_mutex); + pthread_cond_wait(&decoder_cv, &decoder_mutex); + ALOGV("Going to unlock n decodethreadwrite since sink " + "resumed mPaused %d, mIsAudioRouted %d, mReachedEOS %d", + mPaused, mIsAudioRouted, mReachedEOS); + pthread_mutex_unlock(&decoder_mutex); + } + mLock.lock(); + lSeeking = mSeeking||mInternalSeeking; + mLock.unlock(); + + if(lSeeking == false && (killDecoderThread == false)){ + //if we are seeking, ignore write, otherwise write + ALOGV("Fillbuffer before seeling flag %d", mSeeking); + int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten); + ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking); + } else { + ALOGV("Fillbuffer ignored since we seeked after fillBuffer was set %d", mSeeking); + } } } } @@ -580,19 +664,27 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) { return 0; } + if ((data == (void*) NULL) || size > MEM_BUFFER_SIZE) { + ALOGE("fillBuffer given wrong buffer"); + return 0; + } + bool postSeekComplete = false; size_t size_done = 0; size_t size_remaining = size; + ALOGV("fillBuffer: Clearing seek flag in fill buffer"); + while (size_remaining > 0) { MediaSource::ReadOptions options; { Mutex::Autolock autoLock(mLock); - if (mSeeking) { + if(mSeeking) { mInternalSeeking = false; } + if (mSeeking || mInternalSeeking) { if (mIsFirstBuffer) { if (mFirstBuffer != NULL) { @@ -609,8 +701,9 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) { mInputBuffer = NULL; } - size_remaining = size; + // This is to ignore the data already filled in the output buffer size_done = 0; + size_remaining = size; mSeeking = false; if (mObserver && !mInternalSeeking) { @@ -618,6 +711,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) { postSeekComplete = true; } mInternalSeeking = false; + ALOGV("fillBuffer: Setting seek flag in fill buffer"); } } @@ -635,14 +729,16 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) { } CHECK((err == OK && mInputBuffer != NULL) - || (err != OK && mInputBuffer == NULL)); - - Mutex::Autolock autoLock(mLock); - - if (err != OK) { - mReachedEOS = true; - mFinalStatus = err; - break; + || (err != OK && mInputBuffer == NULL)); + { + Mutex::Autolock autoLock(mLock); + + if (err != OK) { + ALOGD("fill buffer - reached eos true"); + mReachedEOS = true; + mFinalStatus = err; + break; + } } CHECK(mInputBuffer->meta_data()->findInt64( @@ -662,7 +758,7 @@ size_t LPAPlayer::fillBuffer(void *data, size_t size) { size_t copy = size_remaining; if (copy > mInputBuffer->range_length()) { copy = mInputBuffer->range_length(); - } + } //is size_remaining < range_length impossible? memcpy((char *)data + size_done, (const char *)mInputBuffer->data() + mInputBuffer->range_offset(), @@ -712,9 +808,7 @@ int64_t LPAPlayer::getTimeStamp(A2DPState state) { return timestamp; } -int64_t LPAPlayer::getMediaTimeUs() { - Mutex::Autolock autoLock(mLock); - ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime); +int64_t LPAPlayer::getMediaTimeUs_l() { if (mPaused) { return mPauseTime; } else { @@ -723,16 +817,21 @@ int64_t LPAPlayer::getMediaTimeUs() { } } -bool LPAPlayer::getMediaTimeMapping( - int64_t *realtime_us, int64_t *mediatime_us) { +int64_t LPAPlayer::getMediaTimeUs() { Mutex::Autolock autoLock(mLock); + ALOGV("getMediaTimeUs() mPaused %d mSeekTimeUs %lld mPauseTime %lld", mPaused, mSeekTimeUs, mPauseTime); + return getMediaTimeUs_l(); +} - *realtime_us = mPositionTimeRealUs; - *mediatime_us = mPositionTimeMediaUs; - - return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1; +bool LPAPlayer::getMediaTimeMapping( + int64_t *realtime_us, int64_t *mediatime_us) { + ALOGE("getMediaTimeMapping is invalid for LPA Player"); + *realtime_us = -1; + *mediatime_us = -1; + return false; } +//lock taken in reset() void LPAPlayer::requestAndWaitForDecoderThreadExit() { if (!decoderThreadAlive) @@ -745,8 +844,10 @@ void LPAPlayer::requestAndWaitForDecoderThreadExit() { mAudioSink->flush(); pthread_cond_signal(&decoder_cv); + mLock.unlock(); pthread_join(decoderThread,NULL); - ALOGV("decoder thread killed"); + mLock.lock(); + ALOGD("decoder thread killed"); } @@ -761,7 +862,7 @@ void LPAPlayer::requestAndWaitForA2DPNotificationThreadExit() { void LPAPlayer::onPauseTimeOut() { ALOGV("onPauseTimeOut"); - Mutex::Autolock autoLock(mResumeLock); + Mutex::Autolock autoLock(mLock); if (!mPauseEventPending) { return; } @@ -790,4 +891,18 @@ void LPAPlayer::onPauseTimeOut() { } +//dup each mono frame +void LPAPlayer::convertMonoToStereo(int16_t *data, size_t size) +{ + int i =0; + int16_t *start_pointer = data; + int monoFrameCount = (size) / (sizeof(int16_t)); + + for (i = monoFrameCount; i > 0 ; i--) { + int16_t temp_sample = *(start_pointer + i - 1); + *(start_pointer + (i*2) - 1) = temp_sample; + *(start_pointer + (i*2) - 2) = temp_sample; + } +} + } //namespace android diff --git a/media/libstagefright/TunnelPlayer.cpp b/media/libstagefright/TunnelPlayer.cpp index c5f8066..3b45db4 100644 --- a/media/libstagefright/TunnelPlayer.cpp +++ b/media/libstagefright/TunnelPlayer.cpp @@ -51,6 +51,13 @@ static const char mName[] = "TunnelPlayer"; #define MEM_METADATA_SIZE 64 #define MEM_PADDING 64 +/* + * We need to reserve some space in the + * ion buffer (used in HAL) to save the + * metadata. so read from the extractor + * a somewhat smaller number of bytes. + * ideally this number should be bufer_size - sizeof(struct output_metadata_t) + */ #define MEM_BUFFER_SIZE (240*1024 - MEM_METADATA_SIZE) #define MEM_BUFFER_COUNT 4 #define TUNNEL_BUFFER_TIME 1500000 @@ -374,7 +381,9 @@ status_t TunnelPlayer::start(bool sourceAlreadyStarted) { status_t TunnelPlayer::seekTo(int64_t time_us) { - ALOGV("seekTo: time_us %lld", time_us); + ALOGD("seekTo: time_us %lld", time_us); + + Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout //This can happen if the client calls seek //without ever calling getPosition @@ -385,19 +394,26 @@ status_t TunnelPlayer::seekTo(int64_t time_us) { if (mPositionTimeRealUs > 0) { //check for return conditions only if seektime // is set + bool postSeekComplete = false; + if (time_us > mPositionTimeRealUs){ - if((time_us - mPositionTimeRealUs) < TUNNEL_BUFFER_TIME){ + if ((time_us - mPositionTimeRealUs) < TUNNEL_BUFFER_TIME){ ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs); - mObserver->postAudioSeekComplete(); - return OK; + postSeekComplete = true; } } else { - if((mPositionTimeRealUs - time_us) < TUNNEL_BUFFER_TIME){ + if ((mPositionTimeRealUs - time_us) < TUNNEL_BUFFER_TIME){ ALOGV("In seekTo(), ignoring time_us %lld mSeekTimeUs %lld", time_us, mSeekTimeUs); - mObserver->postAudioSeekComplete(); - return OK; + postSeekComplete = true; } } + + if (postSeekComplete) { + mLock.unlock(); //unlock and post + mObserver->postAudioSeekComplete(); + mLock.lock(); + return OK; + } } mSeeking = true; @@ -502,6 +518,13 @@ size_t TunnelPlayer::AudioSinkCallback( void TunnelPlayer::reset() { ALOGV("Reset"); + Mutex::Autolock _l(mLock); //to sync w/ onpausetimeout + + //cancel any pending onpause timeout events + //doesnt matter if the event is really present or not + mPauseEventPending = false; + mQueue.cancelEvent(mPauseEvent->eventID()); + mReachedEOS = true; // make sure Decoder thread has exited @@ -568,7 +591,8 @@ void TunnelPlayer::extractorThreadEntry() { uint32_t BufferSizeToUse = MEM_BUFFER_SIZE; pid_t tid = gettid(); - androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO); + androidSetThreadPriority(tid, mHasVideo ? ANDROID_PRIORITY_NORMAL : + ANDROID_PRIORITY_AUDIO); prctl(PR_SET_NAME, (unsigned long)"Extractor Thread", 0, 0, 0); ALOGV("extractorThreadEntry wait for signal \n"); @@ -585,7 +609,7 @@ void TunnelPlayer::extractorThreadEntry() { const char *mime; bool success = format->findCString(kKeyMIMEType, &mime); } - void* local_buf = malloc(BufferSizeToUse + MEM_PADDING); + void* local_buf = malloc(BufferSizeToUse); int *lptr = ((int*)local_buf); int bytesWritten = 0; bool lSeeking = false; @@ -632,8 +656,7 @@ void TunnelPlayer::extractorThreadEntry() { 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)]); + ALOGV("Fillbuffer before seek flag %d", mSeeking); int lWrittenBytes = mAudioSink->write(local_buf, bytesWritten); ALOGV("Fillbuffer after write, written bytes %d and seek flag %d", lWrittenBytes, mSeeking); if(lWrittenBytes > 0) { @@ -660,6 +683,7 @@ void TunnelPlayer::extractorThreadEntry() { } } } + } free(local_buf); @@ -696,11 +720,11 @@ 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"); + bool yield = !mIsFirstBuffer; + while (size_remaining > 0) { MediaSource::ReadOptions options; { @@ -738,7 +762,6 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) { 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) { @@ -787,6 +810,10 @@ size_t TunnelPlayer::fillBuffer(void *data, size_t size) { size_done += copy; size_remaining -= copy; + + if (mHasVideo && yield) { + sched_yield(); + } } if(mReachedEOS) memset((char *)data + size_done, 0x0, size_remaining); @@ -841,7 +868,9 @@ bool TunnelPlayer::getMediaTimeMapping( return mPositionTimeRealUs != -1 && mPositionTimeMediaUs != -1; } +//lock has been taken in reset() to sync with onpausetimeout void TunnelPlayer::requestAndWaitForExtractorThreadExit() { + ALOGV("requestAndWaitForExtractorThreadExit -1"); if (!extractorThreadAlive) return; @@ -856,7 +885,9 @@ void TunnelPlayer::requestAndWaitForExtractorThreadExit() { ALOGV("requestAndWaitForExtractorThreadExit +1"); pthread_cond_signal(&extractor_cv); ALOGV("requestAndWaitForExtractorThreadExit +2"); + mLock.unlock(); pthread_join(extractorThread,NULL); + mLock.lock(); ALOGV("requestAndWaitForExtractorThreadExit +3"); ALOGV("Extractor thread killed"); diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index ee885a5..8bda7f8 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -309,6 +309,9 @@ private: 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(); +#ifdef QCOM_HARDWARE + void checkTunnelExceptions(); +#endif bool mStatistics; struct TrackStat { -- cgit v1.1