X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=blobdiff_plain;f=dali-toolkit%2Finternal%2Fvisuals%2Fanimated-vector-image%2Fvector-animation-task.cpp;h=302fce773eeea03def59403efa99f85ec1b57ac5;hp=8258fb7e5ffb42025b45c8c2b5b703f4ca411767;hb=34a9372d83f9a8a63ef0abcc93c652448e308562;hpb=271110063e8b896a45d7c9116cf4ad53585933bd diff --git a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp index 8258fb7..302fce7 100644 --- a/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp +++ b/dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * Copyright (c) 2022 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,284 +20,329 @@ // EXTERNAL INCLUDES #include +#include +#include // INTERNAL INCLUDES -#include +#include #include +#include namespace Dali { - namespace Toolkit { - namespace Internal { - namespace { - constexpr auto LOOP_FOREVER = -1; -constexpr auto NANOSECONDS_PER_SECOND( 1e+9 ); +constexpr auto MICROSECONDS_PER_SECOND(1e+6); #if defined(DEBUG_ENABLED) -Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" ); +Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VECTOR_ANIMATION"); #endif -template< typename T > -inline void ResetValue( bool& updated, T& value, T newValue, ConditionalWait& conditionalWait ) -{ - ConditionalWait::ScopedLock lock( conditionalWait ); - if( !updated ) - { - value = newValue; - updated = true; - } -} - } // unnamed namespace -VectorAnimationTask::VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url ) -: mUrl( url ), - mVectorRenderer(), - mVectorAnimationThread( factoryCache.GetVectorAnimationThread() ), +VectorAnimationTask::VectorAnimationTask(VisualFactoryCache& factoryCache) +: mUrl(), + mVectorRenderer(VectorAnimationRenderer::New()), + mAnimationData(), + mVectorAnimationThread(factoryCache.GetVectorAnimationManager().GetVectorAnimationThread()), mConditionalWait(), + mResourceReadySignal(), mAnimationFinishedTrigger(), - mPlayState( PlayState::STOPPED ), - mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ), - mLoopingMode( DevelImageVisual::LoopingMode::RESTART ), + mLoadCompletedTrigger(new EventThreadCallback(MakeCallback(this, &VectorAnimationTask::OnLoadCompleted))), + mPlayState(PlayState::STOPPED), + mStopBehavior(DevelImageVisual::StopBehavior::CURRENT_FRAME), + mLoopingMode(DevelImageVisual::LoopingMode::RESTART), mNextFrameStartTime(), - mFrameDurationNanoSeconds( 0 ), - mFrameRate( 60.0f ), - mCurrentFrame( 0 ), - mTotalFrame( 0 ), - mStartFrame( 0 ), - mEndFrame( 0 ), - mWidth( 0 ), - mHeight( 0 ), - mLoopCount( LOOP_FOREVER ), - mCurrentLoop( 0 ), - mResourceReady( false ), - mCurrentFrameUpdated( false ), - mCurrentLoopUpdated( false ), - mForward( true ), - mUpdateFrameNumber( false ), - mNeedAnimationFinishedTrigger( true ) -{ - Initialize(); + mFrameDurationMicroSeconds(MICROSECONDS_PER_SECOND / 60.0f), + mFrameRate(60.0f), + mCurrentFrame(0), + mTotalFrame(0), + mStartFrame(0), + mEndFrame(0), + mDroppedFrames(0), + mWidth(0), + mHeight(0), + mAnimationDataIndex(0), + mLoopCount(LOOP_FOREVER), + mCurrentLoop(0), + mForward(true), + mUpdateFrameNumber(false), + mNeedAnimationFinishedTrigger(true), + mAnimationDataUpdated(false), + mDestroyTask(false), + mLoadRequest(false), + mLoadFailed(false) +{ + mVectorRenderer.UploadCompletedSignal().Connect(this, &VectorAnimationTask::OnUploadCompleted); } VectorAnimationTask::~VectorAnimationTask() { - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this); } void VectorAnimationTask::Finalize() { + ConditionalWait::ScopedLock lock(mConditionalWait); + // Release some objects in the main thread - if( mAnimationFinishedTrigger ) + if(mAnimationFinishedTrigger) { mAnimationFinishedTrigger.reset(); } + if(mLoadCompletedTrigger) + { + mLoadCompletedTrigger.reset(); + } mVectorRenderer.Finalize(); + + mDestroyTask = true; } -void VectorAnimationTask::SetRenderer( Renderer renderer ) +bool VectorAnimationTask::Load() { - ConditionalWait::ScopedLock lock( mConditionalWait ); + if(!mVectorRenderer.Load(mUrl)) + { + DALI_LOG_ERROR("VectorAnimationTask::Load: Load failed [%s]\n", mUrl.c_str()); + mLoadRequest = false; + mLoadFailed = true; + mLoadCompletedTrigger->Trigger(); + return false; + } + + mTotalFrame = mVectorRenderer.GetTotalFrameNumber(); + + mEndFrame = mTotalFrame - 1; + + mFrameRate = mVectorRenderer.GetFrameRate(); + mFrameDurationMicroSeconds = MICROSECONDS_PER_SECOND / mFrameRate; - mVectorRenderer.SetRenderer( renderer ); + mLoadRequest = false; + mLoadCompletedTrigger->Trigger(); - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Load: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this); + + return true; } -void VectorAnimationTask::SetSize( uint32_t width, uint32_t height ) +void VectorAnimationTask::SetRenderer(Renderer renderer) { - if( mWidth != width || mHeight != height ) - { - ConditionalWait::ScopedLock lock( mConditionalWait ); - mVectorRenderer.SetSize( width, height ); + ConditionalWait::ScopedLock lock(mConditionalWait); - mWidth = width; - mHeight = height; + mVectorRenderer.SetRenderer(renderer); - mResourceReady = false; + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this); +} - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this ); - } +void VectorAnimationTask::RequestLoad(const std::string& url) +{ + mUrl = url; + mLoadRequest = true; + + mVectorAnimationThread.AddTask(this); } -void VectorAnimationTask::PlayAnimation() +bool VectorAnimationTask::IsLoadRequested() const { - ConditionalWait::ScopedLock lock( mConditionalWait ); + return mLoadRequest; +} - if( mPlayState != PlayState::PLAYING ) - { - mUpdateFrameNumber = false; - mPlayState = PlayState::PLAYING; +void VectorAnimationTask::SetAnimationData(const AnimationData& data) +{ + ConditionalWait::ScopedLock lock(mConditionalWait); + + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this); + + uint32_t index = mAnimationDataIndex == 0 ? 1 : 0; // Use the other buffer - mVectorAnimationThread.AddTask( this ); + mAnimationData[index] = data; + mAnimationDataUpdated = true; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this ); + if(data.resendFlag & VectorAnimationTask::RESEND_SIZE) + { + // The size should be changed in the main thread. + SetSize(data.width, data.height); } + + mVectorAnimationThread.AddTask(this); } -void VectorAnimationTask::StopAnimation() +void VectorAnimationTask::SetSize(uint32_t width, uint32_t height) { - ConditionalWait::ScopedLock lock( mConditionalWait ); - if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING ) + if(mWidth != width || mHeight != height) { - mNeedAnimationFinishedTrigger = false; - mPlayState = PlayState::STOPPING; + mVectorRenderer.SetSize(width, height); + + mWidth = width; + mHeight = height; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this); } } -void VectorAnimationTask::PauseAnimation() +void VectorAnimationTask::PlayAnimation() { - ConditionalWait::ScopedLock lock( mConditionalWait ); - if( mPlayState == PlayState::PLAYING ) + if(mPlayState != PlayState::PLAYING) { - mPlayState = PlayState::PAUSED; + mNeedAnimationFinishedTrigger = true; + mUpdateFrameNumber = false; + mPlayState = PlayState::PLAYING; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this); } } -void VectorAnimationTask::RenderFrame() +void VectorAnimationTask::StopAnimation() { - ConditionalWait::ScopedLock lock( mConditionalWait ); - - if( !mResourceReady ) + if(mPlayState != PlayState::STOPPING) { - mVectorAnimationThread.AddTask( this ); + mNeedAnimationFinishedTrigger = false; + mPlayState = PlayState::STOPPING; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::RenderFrame: Render [%p]\n", this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this); } } -void VectorAnimationTask::SetAnimationFinishedCallback( EventThreadCallback* callback ) +void VectorAnimationTask::PauseAnimation() { - ConditionalWait::ScopedLock lock( mConditionalWait ); - if( callback ) + if(mPlayState == PlayState::PLAYING) { - mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback ); + mPlayState = PlayState::PAUSED; + + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this); } } -void VectorAnimationTask::SetLoopCount( int32_t count ) +void VectorAnimationTask::SetAnimationFinishedCallback(EventThreadCallback* callback) { - if( mLoopCount != count ) + ConditionalWait::ScopedLock lock(mConditionalWait); + if(callback) { - ConditionalWait::ScopedLock lock( mConditionalWait ); + mAnimationFinishedTrigger = std::unique_ptr(callback); + } +} - mLoopCount = count; +void VectorAnimationTask::SetLoopCount(int32_t count) +{ + if(mLoopCount != count) + { + mLoopCount = count; mCurrentLoop = 0; - mCurrentLoopUpdated = true; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this); } } -void VectorAnimationTask::SetPlayRange( uint32_t startFrame, uint32_t endFrame ) +void VectorAnimationTask::SetPlayRange(const Property::Array& playRange) { - // Make sure the range specified is between 0 and the total frame number - if( ( startFrame < mTotalFrame ) && ( endFrame < mTotalFrame ) ) + bool valid = false; + uint32_t startFrame = 0, endFrame = 0; + size_t count = playRange.Count(); + + if(count >= 2) { - // If the range is not in order swap values - if( startFrame > endFrame ) + int32_t start = 0, end = 0; + if(playRange.GetElementAt(0).Get(start) && playRange.GetElementAt(1).Get(end)) { - uint32_t temp = startFrame; - startFrame = endFrame; - endFrame = temp; + startFrame = static_cast(start); + endFrame = static_cast(end); + valid = true; } - - if( startFrame != mStartFrame || endFrame != mEndFrame ) + else { - ConditionalWait::ScopedLock lock( mConditionalWait ); - - mStartFrame = startFrame; - mEndFrame = endFrame; - - // If the current frame is out of the range, change the current frame also. - if( mStartFrame > mCurrentFrame ) + std::string startMarker, endMarker; + if(playRange.GetElementAt(0).Get(startMarker) && playRange.GetElementAt(1).Get(endMarker)) { - mCurrentFrame = mStartFrame; - - mCurrentFrameUpdated = true; - mResourceReady = false; + if(mVectorRenderer) + { + uint32_t frame; // We don't use this later + if(mVectorRenderer.GetMarkerInfo(startMarker, startFrame, frame) && mVectorRenderer.GetMarkerInfo(endMarker, frame, endFrame)) + { + valid = true; + } + } } - else if( mEndFrame < mCurrentFrame ) + } + } + else if(count == 1) + { + std::string marker; + if(playRange.GetElementAt(0).Get(marker)) + { + if(mVectorRenderer && mVectorRenderer.GetMarkerInfo(marker, startFrame, endFrame)) { - mCurrentFrame = mEndFrame; - - mCurrentFrameUpdated = true; - mResourceReady = false; + valid = true; } - - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this ); } } -} -void VectorAnimationTask::GetPlayRange( uint32_t& startFrame, uint32_t& endFrame ) -{ - startFrame = mStartFrame; - endFrame = mEndFrame; -} + if(!valid) + { + DALI_LOG_ERROR("VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this); + return; + } -DevelImageVisual::PlayState::Type VectorAnimationTask::GetPlayState() const -{ - DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED; + // Make sure the range specified is between 0 and the total frame number + startFrame = std::min(startFrame, mTotalFrame - 1); + endFrame = std::min(endFrame, mTotalFrame - 1); - switch( mPlayState ) + // If the range is not in order swap values + if(startFrame > endFrame) { - case PlayState::PLAYING: - { - state = DevelImageVisual::PlayState::PLAYING; - break; - } - case PlayState::PAUSED: + uint32_t temp = startFrame; + startFrame = endFrame; + endFrame = temp; + } + + if(startFrame != mStartFrame || endFrame != mEndFrame) + { + mStartFrame = startFrame; + mEndFrame = endFrame; + + // If the current frame is out of the range, change the current frame also. + if(mStartFrame > mCurrentFrame) { - state = DevelImageVisual::PlayState::PAUSED; - break; + mCurrentFrame = mStartFrame; } - case PlayState::STOPPING: - case PlayState::STOPPED: + else if(mEndFrame < mCurrentFrame) { - state = DevelImageVisual::PlayState::STOPPED; - break; + mCurrentFrame = mEndFrame; } - } - return state; + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%s] [%p]\n", mStartFrame, mEndFrame, mUrl.c_str(), this); + } } -void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber ) +void VectorAnimationTask::GetPlayRange(uint32_t& startFrame, uint32_t& endFrame) { - ConditionalWait::ScopedLock lock( mConditionalWait ); + startFrame = mStartFrame; + endFrame = mEndFrame; +} - if( mCurrentFrame == frameNumber ) +void VectorAnimationTask::SetCurrentFrameNumber(uint32_t frameNumber) +{ + if(mCurrentFrame == frameNumber) { - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this); return; } - if( frameNumber >= mStartFrame && frameNumber <= mEndFrame ) + if(frameNumber >= mStartFrame && frameNumber <= mEndFrame) { - mCurrentFrame = frameNumber; - mCurrentFrameUpdated = true; - + mCurrentFrame = frameNumber; mUpdateFrameNumber = false; - mResourceReady = false; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this); } else { - DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame ); + DALI_LOG_ERROR("Invalid frame number [%d (%d, %d)] [%p]\n", frameNumber, mStartFrame, mEndFrame, this); } } @@ -311,133 +356,116 @@ uint32_t VectorAnimationTask::GetTotalFrameNumber() const return mTotalFrame; } -void VectorAnimationTask::GetDefaultSize( uint32_t& width, uint32_t& height ) const +void VectorAnimationTask::GetDefaultSize(uint32_t& width, uint32_t& height) const { - mVectorRenderer.GetDefaultSize( width, height ); + mVectorRenderer.GetDefaultSize(width, height); } -void VectorAnimationTask::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior ) +void VectorAnimationTask::SetStopBehavior(DevelImageVisual::StopBehavior::Type stopBehavior) { - ConditionalWait::ScopedLock lock( mConditionalWait ); mStopBehavior = stopBehavior; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this); } -void VectorAnimationTask::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode ) +void VectorAnimationTask::SetLoopingMode(DevelImageVisual::LoopingMode::Type loopingMode) { - ConditionalWait::ScopedLock lock( mConditionalWait ); mLoopingMode = loopingMode; - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this); } -void VectorAnimationTask::GetLayerInfo( Property::Map& map ) const +void VectorAnimationTask::GetLayerInfo(Property::Map& map) const { - mVectorRenderer.GetLayerInfo( map ); + mVectorRenderer.GetLayerInfo(map); } -VectorAnimationTask::UploadCompletedSignalType& VectorAnimationTask::UploadCompletedSignal() +VectorAnimationTask::ResourceReadySignalType& VectorAnimationTask::ResourceReadySignal() { - return mVectorRenderer.UploadCompletedSignal(); -} - -void VectorAnimationTask::Initialize() -{ - mVectorRenderer = VectorAnimationRenderer::New( mUrl ); - - mTotalFrame = mVectorRenderer.GetTotalFrameNumber(); - - mEndFrame = mTotalFrame - 1; - - mFrameRate = mVectorRenderer.GetFrameRate(); - mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate; - - uint32_t width, height; - mVectorRenderer.GetDefaultSize( width, height ); - - SetSize( width, height ); - - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this ); + return mResourceReadySignal; } -bool VectorAnimationTask::Rasterize() +bool VectorAnimationTask::Rasterize(bool& keepAnimation) { - bool stopped = false, needAnimationFinishedTrigger; - uint32_t currentFrame, startFrame, endFrame; - int32_t loopCount, currentLoopCount; - PlayState playState; + bool stopped = false; + uint32_t currentFrame; + keepAnimation = false; { - ConditionalWait::ScopedLock lock( mConditionalWait ); + ConditionalWait::ScopedLock lock(mConditionalWait); + if(mDestroyTask) + { + // The task will be destroyed. We don't need rasterization. + return false; + } - if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber ) + if(mLoadRequest) { - mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1; + return Load(); } + } - currentFrame = mCurrentFrame; - startFrame = mStartFrame; - endFrame = mEndFrame; - loopCount = mLoopCount; - currentLoopCount = mCurrentLoop; - needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger; - playState = mPlayState; - - mResourceReady = true; - mCurrentFrameUpdated = false; - mCurrentLoopUpdated = false; - mUpdateFrameNumber = true; - mNeedAnimationFinishedTrigger = true; + if(mLoadFailed) + { + return false; } - if( playState == PlayState::STOPPING ) + ApplyAnimationData(); + + if(mPlayState == PlayState::PLAYING && mUpdateFrameNumber) { - currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame ); - ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait ); + mCurrentFrame = mForward ? mCurrentFrame + mDroppedFrames + 1 : (mCurrentFrame > mDroppedFrames ? mCurrentFrame - mDroppedFrames - 1 : 0); + Dali::ClampInPlace(mCurrentFrame, mStartFrame, mEndFrame); + } + + currentFrame = mCurrentFrame; - stopped = true; + mUpdateFrameNumber = true; + + if(mPlayState == PlayState::STOPPING) + { + mCurrentFrame = GetStoppedFrame(mStartFrame, mEndFrame, mCurrentFrame); + currentFrame = mCurrentFrame; + stopped = true; } - else if( playState == PlayState::PLAYING ) + else if(mPlayState == PlayState::PLAYING) { bool animationFinished = false; - if( currentFrame >= endFrame ) // last frame + if(currentFrame >= mEndFrame) // last frame { - if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE ) + if(mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE) { mForward = false; } else { - if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop + if(mLoopCount < 0 || ++mCurrentLoop < mLoopCount) // repeat forever or before the last loop { - ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait ); // If the current frame is changed in the event thread, don't overwrite it. + mCurrentFrame = mStartFrame; mUpdateFrameNumber = false; } else { - animationFinished = true; // end of animation + animationFinished = true; // end of animation } - ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait ); } } - else if( currentFrame == startFrame && !mForward ) // first frame + else if(currentFrame == mStartFrame && !mForward) // first frame { - if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop + if(mLoopCount < 0 || ++mCurrentLoop < mLoopCount) // repeat forever or before the last loop { mForward = true; } else { - animationFinished = true; // end of animation + animationFinished = true; // end of animation } - ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait ); } - if( animationFinished ) + if(animationFinished) { - if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME ) + if(mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME) { stopped = true; } @@ -450,45 +478,47 @@ bool VectorAnimationTask::Rasterize() // Rasterize bool renderSuccess = false; - if( mVectorRenderer ) + if(mVectorRenderer) { - renderSuccess = mVectorRenderer.Render( currentFrame ); - if( !renderSuccess ) + renderSuccess = mVectorRenderer.Render(currentFrame); + if(!renderSuccess) { - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this); mUpdateFrameNumber = false; } } - if( stopped && renderSuccess ) + if(stopped && renderSuccess) { - mPlayState = PlayState::STOPPED; - mForward = true; + mPlayState = PlayState::STOPPED; + mForward = true; mCurrentLoop = 0; // Animation is finished - if( needAnimationFinishedTrigger && mAnimationFinishedTrigger ) { - mAnimationFinishedTrigger->Trigger(); + ConditionalWait::ScopedLock lock(mConditionalWait); + if(mNeedAnimationFinishedTrigger && mAnimationFinishedTrigger) + { + mAnimationFinishedTrigger->Trigger(); + } } - DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this ); + DALI_LOG_INFO(gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this); } - bool keepAnimation = true; - if( playState == PlayState::PAUSED || playState == PlayState::STOPPED ) + if(mPlayState != PlayState::PAUSED && mPlayState != PlayState::STOPPED) { - keepAnimation = false; + keepAnimation = true; } - return keepAnimation; + return true; } -uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame ) +uint32_t VectorAnimationTask::GetStoppedFrame(uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame) { uint32_t frame = currentFrame; - switch( mStopBehavior ) + switch(mStopBehavior) { case DevelImageVisual::StopBehavior::FIRST_FRAME: { @@ -497,7 +527,7 @@ uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t end } case DevelImageVisual::StopBehavior::LAST_FRAME: { - if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE ) + if(mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE) { frame = startFrame; } @@ -517,26 +547,125 @@ uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t end return frame; } -std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::CalculateNextFrameTime( bool renderNow ) +VectorAnimationTask::TimePoint VectorAnimationTask::CalculateNextFrameTime(bool renderNow) { - // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported + // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::steady_clock supported // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime // is casted to use the default duration. - mNextFrameStartTime = std::chrono::time_point_cast< std::chrono::time_point< std::chrono::system_clock >::duration >( - mNextFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds ) ); - auto current = std::chrono::system_clock::now(); - if( renderNow || mNextFrameStartTime < current ) + mNextFrameStartTime = std::chrono::time_point_cast(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds)); + auto current = std::chrono::steady_clock::now(); + mDroppedFrames = 0; + + if(renderNow) + { + mNextFrameStartTime = current; + } + else if(mNextFrameStartTime < current) { + uint32_t droppedFrames = 0; + + while(current > std::chrono::time_point_cast(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds)) && droppedFrames < mTotalFrame) + { + droppedFrames++; + mNextFrameStartTime = std::chrono::time_point_cast(mNextFrameStartTime + std::chrono::microseconds(mFrameDurationMicroSeconds)); + } + mNextFrameStartTime = current; + mDroppedFrames = droppedFrames; } + return mNextFrameStartTime; } -std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::GetNextFrameTime() +VectorAnimationTask::TimePoint VectorAnimationTask::GetNextFrameTime() { return mNextFrameStartTime; } +void VectorAnimationTask::ApplyAnimationData() +{ + uint32_t index; + + { + ConditionalWait::ScopedLock lock(mConditionalWait); + + if(!mAnimationDataUpdated || mAnimationData[mAnimationDataIndex].resendFlag != 0) + { + // Data is not updated or the previous data is not applied yet. + return; + } + + mAnimationDataIndex = mAnimationDataIndex == 0 ? 1 : 0; // Swap index + mAnimationDataUpdated = false; + + index = mAnimationDataIndex; + } + + if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT) + { + SetLoopCount(mAnimationData[index].loopCount); + } + + if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE) + { + SetPlayRange(mAnimationData[index].playRange); + } + + if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR) + { + SetStopBehavior(mAnimationData[index].stopBehavior); + } + + if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE) + { + SetLoopingMode(mAnimationData[index].loopingMode); + } + + if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME) + { + SetCurrentFrameNumber(mAnimationData[index].currentFrame); + } + + if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_NEED_RESOURCE_READY) + { + mVectorRenderer.InvalidateBuffer(); + } + + if(mAnimationData[index].resendFlag & VectorAnimationTask::RESEND_PLAY_STATE) + { + if(mAnimationData[index].playState == DevelImageVisual::PlayState::PLAYING) + { + PlayAnimation(); + } + else if(mAnimationData[index].playState == DevelImageVisual::PlayState::PAUSED) + { + PauseAnimation(); + } + else if(mAnimationData[index].playState == DevelImageVisual::PlayState::STOPPED) + { + StopAnimation(); + } + } + + mAnimationData[index].resendFlag = 0; +} + +void VectorAnimationTask::OnUploadCompleted() +{ + mResourceReadySignal.Emit(ResourceStatus::READY); +} + +void VectorAnimationTask::OnLoadCompleted() +{ + if(!mLoadFailed) + { + mResourceReadySignal.Emit(ResourceStatus::LOADED); + } + else + { + mResourceReadySignal.Emit(ResourceStatus::FAILED); + } +} } // namespace Internal } // namespace Toolkit