2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/object/property-array.h>
24 #include <dali/public-api/math/math-utils.h>
27 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
28 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
42 constexpr auto LOOP_FOREVER = -1;
43 constexpr auto NANOSECONDS_PER_SECOND( 1e+9 );
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
49 template< typename T >
50 inline void ResetValue( bool& updated, T& value, T newValue, ConditionalWait& conditionalWait )
52 ConditionalWait::ScopedLock lock( conditionalWait );
60 } // unnamed namespace
62 VectorAnimationTask::VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url )
65 mVectorAnimationThread( factoryCache.GetVectorAnimationThread() ),
67 mAnimationFinishedTrigger(),
68 mPlayState( PlayState::STOPPED ),
69 mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
70 mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
71 mNextFrameStartTime(),
72 mFrameDurationNanoSeconds( 0 ),
80 mLoopCount( LOOP_FOREVER ),
82 mResourceReady( false ),
83 mCurrentFrameUpdated( false ),
84 mCurrentLoopUpdated( false ),
86 mUpdateFrameNumber( false ),
87 mNeedAnimationFinishedTrigger( true )
92 VectorAnimationTask::~VectorAnimationTask()
94 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this );
97 void VectorAnimationTask::Finalize()
99 ConditionalWait::ScopedLock lock( mConditionalWait );
101 // Release some objects in the main thread
102 if( mAnimationFinishedTrigger )
104 mAnimationFinishedTrigger.reset();
107 mVectorRenderer.Finalize();
110 void VectorAnimationTask::SetRenderer( Renderer renderer )
112 ConditionalWait::ScopedLock lock( mConditionalWait );
114 mVectorRenderer.SetRenderer( renderer );
116 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this );
119 void VectorAnimationTask::SetAnimationData( const AnimationData& data )
121 ConditionalWait::ScopedLock lock( mConditionalWait );
123 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this );
125 if( data.resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT )
127 SetLoopCount( data.loopCount );
130 if( data.resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE )
132 SetPlayRange( data.playRange );
135 if( data.resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR )
137 SetStopBehavior( data.stopBehavior );
140 if( data.resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE )
142 SetLoopingMode( data.loopingMode );
145 if( data.resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME )
147 SetCurrentFrameNumber( data.currentFrame );
150 if( data.resendFlag & VectorAnimationTask::RESEND_SIZE )
152 SetSize( data.width, data.height );
155 if( data.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE )
157 if( data.playState == DevelImageVisual::PlayState::PLAYING )
161 else if( data.playState == DevelImageVisual::PlayState::PAUSED )
166 else if( data.playState == DevelImageVisual::PlayState::STOPPED )
173 if( mPlayState == PlayState::PAUSED || mPlayState == PlayState::STOPPED )
180 void VectorAnimationTask::SetSize( uint32_t width, uint32_t height )
182 if( mWidth != width || mHeight != height )
184 mVectorRenderer.SetSize( width, height );
189 mResourceReady = false;
191 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this );
195 void VectorAnimationTask::PlayAnimation()
197 if( mPlayState != PlayState::PLAYING )
199 mUpdateFrameNumber = false;
200 mPlayState = PlayState::PLAYING;
202 mVectorAnimationThread.AddTask( this );
204 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this );
208 void VectorAnimationTask::StopAnimation()
210 if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING )
212 mNeedAnimationFinishedTrigger = false;
213 mPlayState = PlayState::STOPPING;
215 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this );
219 void VectorAnimationTask::PauseAnimation()
221 if( mPlayState == PlayState::PLAYING )
223 mPlayState = PlayState::PAUSED;
225 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this );
229 void VectorAnimationTask::RenderFrame()
231 if( !mResourceReady )
233 mVectorAnimationThread.AddTask( this );
235 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::RenderFrame: Render [%p]\n", this );
239 void VectorAnimationTask::SetAnimationFinishedCallback( EventThreadCallback* callback )
241 ConditionalWait::ScopedLock lock( mConditionalWait );
244 mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
248 void VectorAnimationTask::SetLoopCount( int32_t count )
250 if( mLoopCount != count )
254 mCurrentLoopUpdated = true;
256 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this );
260 void VectorAnimationTask::SetPlayRange( const Property::Array& playRange )
263 uint32_t startFrame = 0, endFrame = 0;
264 size_t count = playRange.Count();
268 int32_t start = 0, end = 0;
269 if( playRange.GetElementAt( 0 ).Get( start ) && playRange.GetElementAt( 1 ).Get( end ) )
271 startFrame = static_cast< uint32_t >( start );
272 endFrame = static_cast< uint32_t >( end );
277 std::string startMarker, endMarker;
278 if( playRange.GetElementAt( 0 ).Get( startMarker ) && playRange.GetElementAt( 1 ).Get( endMarker ) )
280 if( mVectorRenderer )
282 uint32_t frame; // We don't use this later
283 if( mVectorRenderer.GetMarkerInfo( startMarker, startFrame, frame ) && mVectorRenderer.GetMarkerInfo( endMarker, frame, endFrame ) )
291 else if( count == 1 )
294 if( playRange.GetElementAt( 0 ).Get( marker ) )
296 if( mVectorRenderer )
298 mVectorRenderer.GetMarkerInfo( marker, startFrame, endFrame );
306 DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this );
310 // Make sure the range specified is between 0 and the total frame number
311 if( startFrame >= 0 && startFrame < mTotalFrame && endFrame >= 0 && endFrame < mTotalFrame )
313 // If the range is not in order swap values
314 if( startFrame > endFrame )
316 uint32_t temp = startFrame;
317 startFrame = endFrame;
321 if( startFrame != mStartFrame || endFrame != mEndFrame )
323 mStartFrame = startFrame;
324 mEndFrame = endFrame;
326 // If the current frame is out of the range, change the current frame also.
327 if( mStartFrame > mCurrentFrame )
329 mCurrentFrame = mStartFrame;
331 mCurrentFrameUpdated = true;
332 mResourceReady = false;
334 else if( mEndFrame < mCurrentFrame )
336 mCurrentFrame = mEndFrame;
338 mCurrentFrameUpdated = true;
339 mResourceReady = false;
342 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
347 DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range (%d, %d) [%p]\n", startFrame, endFrame, this );
352 void VectorAnimationTask::GetPlayRange( uint32_t& startFrame, uint32_t& endFrame )
354 startFrame = mStartFrame;
355 endFrame = mEndFrame;
358 DevelImageVisual::PlayState::Type VectorAnimationTask::GetPlayState() const
360 DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED;
364 case PlayState::PLAYING:
366 state = DevelImageVisual::PlayState::PLAYING;
369 case PlayState::PAUSED:
371 state = DevelImageVisual::PlayState::PAUSED;
374 case PlayState::STOPPING:
375 case PlayState::STOPPED:
377 state = DevelImageVisual::PlayState::STOPPED;
385 void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber )
387 if( mCurrentFrame == frameNumber )
389 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
393 if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
395 mCurrentFrame = frameNumber;
396 mCurrentFrameUpdated = true;
398 mUpdateFrameNumber = false;
399 mResourceReady = false;
401 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
405 DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
409 uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
411 return mCurrentFrame;
414 uint32_t VectorAnimationTask::GetTotalFrameNumber() const
419 void VectorAnimationTask::GetDefaultSize( uint32_t& width, uint32_t& height ) const
421 mVectorRenderer.GetDefaultSize( width, height );
424 void VectorAnimationTask::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
426 mStopBehavior = stopBehavior;
428 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
431 void VectorAnimationTask::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
433 mLoopingMode = loopingMode;
435 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
438 void VectorAnimationTask::GetLayerInfo( Property::Map& map ) const
440 mVectorRenderer.GetLayerInfo( map );
443 VectorAnimationTask::UploadCompletedSignalType& VectorAnimationTask::UploadCompletedSignal()
445 return mVectorRenderer.UploadCompletedSignal();
448 void VectorAnimationTask::Initialize()
450 mVectorRenderer = VectorAnimationRenderer::New( mUrl );
452 mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
454 mEndFrame = mTotalFrame - 1;
456 mFrameRate = mVectorRenderer.GetFrameRate();
457 mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
459 uint32_t width, height;
460 mVectorRenderer.GetDefaultSize( width, height );
462 SetSize( width, height );
464 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
467 bool VectorAnimationTask::Rasterize()
469 bool stopped = false, needAnimationFinishedTrigger, resourceReady;
470 uint32_t currentFrame, startFrame, endFrame;
471 int32_t loopCount, currentLoopCount;
475 ConditionalWait::ScopedLock lock( mConditionalWait );
477 if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
479 mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
480 Dali::ClampInPlace( mCurrentFrame, mStartFrame, mEndFrame );
483 currentFrame = mCurrentFrame;
484 startFrame = mStartFrame;
485 endFrame = mEndFrame;
486 loopCount = mLoopCount;
487 currentLoopCount = mCurrentLoop;
488 needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger;
489 playState = mPlayState;
490 resourceReady = mResourceReady;
492 mResourceReady = true;
493 mCurrentFrameUpdated = false;
494 mCurrentLoopUpdated = false;
495 mUpdateFrameNumber = true;
496 mNeedAnimationFinishedTrigger = true;
499 if( playState == PlayState::STOPPING )
501 currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame );
502 ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait );
506 else if( playState == PlayState::PLAYING )
508 bool animationFinished = false;
510 if( currentFrame >= endFrame ) // last frame
512 if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
518 if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop
520 ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait ); // If the current frame is changed in the event thread, don't overwrite it.
521 mUpdateFrameNumber = false;
525 animationFinished = true; // end of animation
527 ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
530 else if( currentFrame == startFrame && !mForward ) // first frame
532 if( loopCount < 0 || ++currentLoopCount < loopCount ) // repeat forever or before the last loop
538 animationFinished = true; // end of animation
540 ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
543 if( animationFinished )
545 if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
551 mPlayState = PlayState::STOPPING;
557 bool renderSuccess = false;
558 if( mVectorRenderer )
560 renderSuccess = mVectorRenderer.Render( currentFrame );
563 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
564 mUpdateFrameNumber = false;
568 ConditionalWait::ScopedLock lock( mConditionalWait );
569 mResourceReady = false;
574 if( stopped && renderSuccess )
576 ConditionalWait::ScopedLock lock( mConditionalWait );
578 mPlayState = PlayState::STOPPED;
582 // Animation is finished
583 if( needAnimationFinishedTrigger && mAnimationFinishedTrigger )
585 mAnimationFinishedTrigger->Trigger();
588 DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
591 bool keepAnimation = true;
592 if( playState == PlayState::PAUSED || playState == PlayState::STOPPED )
594 keepAnimation = false;
597 return keepAnimation;
600 uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
602 uint32_t frame = currentFrame;
604 switch( mStopBehavior )
606 case DevelImageVisual::StopBehavior::FIRST_FRAME:
611 case DevelImageVisual::StopBehavior::LAST_FRAME:
613 if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
623 case DevelImageVisual::StopBehavior::CURRENT_FRAME:
625 frame = currentFrame;
633 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::CalculateNextFrameTime( bool renderNow )
635 // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported
636 // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
637 // is casted to use the default duration.
638 mNextFrameStartTime = std::chrono::time_point_cast< std::chrono::time_point< std::chrono::system_clock >::duration >(
639 mNextFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds ) );
640 auto current = std::chrono::system_clock::now();
641 if( renderNow || mNextFrameStartTime < current )
643 mNextFrameStartTime = current;
645 return mNextFrameStartTime;
648 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::GetNextFrameTime()
650 return mNextFrameStartTime;
653 } // namespace Internal
655 } // namespace Toolkit