ae66146329a0ebb04b6b9cb9c91825789790b40e
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / visuals / animated-vector-image / vector-animation-task.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-task.h>
20
21 // EXTERNAL INCLUDES
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>
25
26 // INTERNAL INCLUDES
27 #include <dali-toolkit/internal/visuals/image-visual-shader-factory.h>
28 #include <dali-toolkit/internal/visuals/animated-vector-image/vector-animation-thread.h>
29
30 namespace Dali
31 {
32
33 namespace Toolkit
34 {
35
36 namespace Internal
37 {
38
39 namespace
40 {
41
42 constexpr auto LOOP_FOREVER = -1;
43 constexpr auto NANOSECONDS_PER_SECOND( 1e+9 );
44
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gVectorAnimationLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_VECTOR_ANIMATION" );
47 #endif
48
49 template< typename T >
50 inline void ResetValue( bool& updated, T& value, T newValue, ConditionalWait& conditionalWait )
51 {
52   ConditionalWait::ScopedLock lock( conditionalWait );
53   if( !updated )
54   {
55     value = newValue;
56     updated = true;
57   }
58 }
59
60 } // unnamed namespace
61
62 VectorAnimationTask::VectorAnimationTask( VisualFactoryCache& factoryCache, const std::string& url )
63 : mUrl( url ),
64   mVectorRenderer(),
65   mVectorAnimationThread( factoryCache.GetVectorAnimationThread() ),
66   mConditionalWait(),
67   mAnimationFinishedTrigger(),
68   mPlayState( PlayState::STOPPED ),
69   mStopBehavior( DevelImageVisual::StopBehavior::CURRENT_FRAME ),
70   mLoopingMode( DevelImageVisual::LoopingMode::RESTART ),
71   mNextFrameStartTime(),
72   mFrameDurationNanoSeconds( 0 ),
73   mFrameRate( 60.0f ),
74   mCurrentFrame( 0 ),
75   mTotalFrame( 0 ),
76   mStartFrame( 0 ),
77   mEndFrame( 0 ),
78   mWidth( 0 ),
79   mHeight( 0 ),
80   mLoopCount( LOOP_FOREVER ),
81   mCurrentLoop( 0 ),
82   mResourceReady( false ),
83   mCurrentFrameUpdated( false ),
84   mCurrentLoopUpdated( false ),
85   mForward( true ),
86   mUpdateFrameNumber( false ),
87   mNeedAnimationFinishedTrigger( true )
88 {
89   Initialize();
90 }
91
92 VectorAnimationTask::~VectorAnimationTask()
93 {
94   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this );
95 }
96
97 void VectorAnimationTask::Finalize()
98 {
99   // Release some objects in the main thread
100   if( mAnimationFinishedTrigger )
101   {
102     mAnimationFinishedTrigger.reset();
103   }
104
105   mVectorRenderer.Finalize();
106 }
107
108 void VectorAnimationTask::SetRenderer( Renderer renderer )
109 {
110   ConditionalWait::ScopedLock lock( mConditionalWait );
111
112   mVectorRenderer.SetRenderer( renderer );
113
114   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this );
115 }
116
117 void VectorAnimationTask::SetSize( uint32_t width, uint32_t height )
118 {
119   if( mWidth != width || mHeight != height )
120   {
121     ConditionalWait::ScopedLock lock( mConditionalWait );
122     mVectorRenderer.SetSize( width, height );
123
124     mWidth = width;
125     mHeight = height;
126
127     mResourceReady = false;
128
129     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this );
130   }
131 }
132
133 void VectorAnimationTask::PlayAnimation()
134 {
135   ConditionalWait::ScopedLock lock( mConditionalWait );
136
137   if( mPlayState != PlayState::PLAYING )
138   {
139     mUpdateFrameNumber = false;
140     mPlayState = PlayState::PLAYING;
141
142     mVectorAnimationThread.AddTask( this );
143
144     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this );
145   }
146 }
147
148 void VectorAnimationTask::StopAnimation()
149 {
150   ConditionalWait::ScopedLock lock( mConditionalWait );
151   if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING )
152   {
153     mNeedAnimationFinishedTrigger = false;
154     mPlayState = PlayState::STOPPING;
155
156     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this );
157   }
158 }
159
160 void VectorAnimationTask::PauseAnimation()
161 {
162   ConditionalWait::ScopedLock lock( mConditionalWait );
163   if( mPlayState == PlayState::PLAYING )
164   {
165     mPlayState = PlayState::PAUSED;
166
167     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this );
168   }
169 }
170
171 void VectorAnimationTask::RenderFrame()
172 {
173   ConditionalWait::ScopedLock lock( mConditionalWait );
174
175   if( !mResourceReady )
176   {
177     mVectorAnimationThread.AddTask( this );
178
179     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::RenderFrame: Render [%p]\n", this );
180   }
181 }
182
183 void VectorAnimationTask::SetAnimationFinishedCallback( EventThreadCallback* callback )
184 {
185   ConditionalWait::ScopedLock lock( mConditionalWait );
186   if( callback )
187   {
188     mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
189   }
190 }
191
192 void VectorAnimationTask::SetLoopCount( int32_t count )
193 {
194   if( mLoopCount != count )
195   {
196     ConditionalWait::ScopedLock lock( mConditionalWait );
197
198     mLoopCount = count;
199     mCurrentLoop = 0;
200     mCurrentLoopUpdated = true;
201
202     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this );
203   }
204 }
205
206 void VectorAnimationTask::SetPlayRange( Property::Array& playRange )
207 {
208   ConditionalWait::ScopedLock lock( mConditionalWait );
209
210   bool valid = false;
211   uint32_t startFrame = 0, endFrame = 0;
212   size_t count = playRange.Count();
213
214   if( count >= 2 )
215   {
216     int32_t start = 0, end = 0;
217     if( playRange.GetElementAt( 0 ).Get( start ) && playRange.GetElementAt( 1 ).Get( end ) )
218     {
219       startFrame = static_cast< uint32_t >( start );
220       endFrame = static_cast< uint32_t >( end );
221       valid = true;
222     }
223     else
224     {
225       std::string startMarker, endMarker;
226       if( playRange.GetElementAt( 0 ).Get( startMarker ) && playRange.GetElementAt( 1 ).Get( endMarker ) )
227       {
228         if( mVectorRenderer )
229         {
230           uint32_t frame;   // We don't use this later
231           if( mVectorRenderer.GetMarkerInfo( startMarker, startFrame, frame ) && mVectorRenderer.GetMarkerInfo( endMarker, frame, endFrame ) )
232           {
233             valid = true;
234           }
235         }
236       }
237     }
238   }
239   else if( count == 1 )
240   {
241     std::string marker;
242     if( playRange.GetElementAt( 0 ).Get( marker ) )
243     {
244       if( mVectorRenderer )
245       {
246         mVectorRenderer.GetMarkerInfo( marker, startFrame, endFrame );
247         valid = true;
248       }
249     }
250   }
251
252   if( !valid )
253   {
254     DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this );
255     return;
256   }
257
258   // Make sure the range specified is between 0 and the total frame number
259   if( startFrame < mTotalFrame && endFrame < mTotalFrame )
260   {
261     // If the range is not in order swap values
262     if( startFrame > endFrame )
263     {
264       uint32_t temp = startFrame;
265       startFrame = endFrame;
266       endFrame = temp;
267     }
268
269     if( startFrame != mStartFrame || endFrame != mEndFrame )
270     {
271       mStartFrame = startFrame;
272       mEndFrame = endFrame;
273
274       // If the current frame is out of the range, change the current frame also.
275       if( mStartFrame > mCurrentFrame )
276       {
277         mCurrentFrame = mStartFrame;
278
279         mCurrentFrameUpdated = true;
280         mResourceReady = false;
281       }
282       else if( mEndFrame < mCurrentFrame )
283       {
284         mCurrentFrame = mEndFrame;
285
286         mCurrentFrameUpdated = true;
287         mResourceReady = false;
288       }
289
290       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
291     }
292   }
293   else
294   {
295     DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range (%d, %d) [%p]\n", startFrame, endFrame, this );
296     return;
297   }
298 }
299
300 void VectorAnimationTask::GetPlayRange( uint32_t& startFrame, uint32_t& endFrame )
301 {
302   startFrame = mStartFrame;
303   endFrame = mEndFrame;
304 }
305
306 DevelImageVisual::PlayState::Type VectorAnimationTask::GetPlayState() const
307 {
308   DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED;
309
310   switch( mPlayState )
311   {
312     case PlayState::PLAYING:
313     {
314       state = DevelImageVisual::PlayState::PLAYING;
315       break;
316     }
317     case PlayState::PAUSED:
318     {
319       state = DevelImageVisual::PlayState::PAUSED;
320       break;
321     }
322     case PlayState::STOPPING:
323     case PlayState::STOPPED:
324     {
325       state = DevelImageVisual::PlayState::STOPPED;
326       break;
327     }
328   }
329
330   return state;
331 }
332
333 void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber )
334 {
335   ConditionalWait::ScopedLock lock( mConditionalWait );
336
337   if( mCurrentFrame == frameNumber )
338   {
339     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
340     return;
341   }
342
343   if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
344   {
345     mCurrentFrame = frameNumber;
346     mCurrentFrameUpdated = true;
347
348     mUpdateFrameNumber = false;
349     mResourceReady = false;
350
351     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
352   }
353   else
354   {
355     DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
356   }
357 }
358
359 uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
360 {
361   return mCurrentFrame;
362 }
363
364 uint32_t VectorAnimationTask::GetTotalFrameNumber() const
365 {
366   return mTotalFrame;
367 }
368
369 void VectorAnimationTask::GetDefaultSize( uint32_t& width, uint32_t& height ) const
370 {
371   mVectorRenderer.GetDefaultSize( width, height );
372 }
373
374 void VectorAnimationTask::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
375 {
376   ConditionalWait::ScopedLock lock( mConditionalWait );
377   mStopBehavior = stopBehavior;
378
379   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
380 }
381
382 void VectorAnimationTask::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
383 {
384   ConditionalWait::ScopedLock lock( mConditionalWait );
385   mLoopingMode = loopingMode;
386
387   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
388 }
389
390 void VectorAnimationTask::GetLayerInfo( Property::Map& map ) const
391 {
392   mVectorRenderer.GetLayerInfo( map );
393 }
394
395 VectorAnimationTask::UploadCompletedSignalType& VectorAnimationTask::UploadCompletedSignal()
396 {
397   return mVectorRenderer.UploadCompletedSignal();
398 }
399
400 void VectorAnimationTask::Initialize()
401 {
402   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
403
404   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
405
406   mEndFrame = mTotalFrame - 1;
407
408   mFrameRate = mVectorRenderer.GetFrameRate();
409   mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
410
411   uint32_t width, height;
412   mVectorRenderer.GetDefaultSize( width, height );
413
414   SetSize( width, height );
415
416   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
417 }
418
419 bool VectorAnimationTask::Rasterize()
420 {
421   bool stopped = false, needAnimationFinishedTrigger;
422   uint32_t currentFrame, startFrame, endFrame;
423   int32_t loopCount, currentLoopCount;
424   PlayState playState;
425
426   {
427     ConditionalWait::ScopedLock lock( mConditionalWait );
428
429     if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
430     {
431       mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
432       Dali::ClampInPlace( mCurrentFrame, mStartFrame, mEndFrame );
433     }
434
435     currentFrame = mCurrentFrame;
436     startFrame = mStartFrame;
437     endFrame = mEndFrame;
438     loopCount = mLoopCount;
439     currentLoopCount = mCurrentLoop;
440     needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger;
441     playState = mPlayState;
442
443     mResourceReady = true;
444     mCurrentFrameUpdated = false;
445     mCurrentLoopUpdated = false;
446     mUpdateFrameNumber = true;
447     mNeedAnimationFinishedTrigger = true;
448   }
449
450   if( playState == PlayState::STOPPING )
451   {
452     currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame );
453     ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait );
454
455     stopped = true;
456   }
457   else if( playState == PlayState::PLAYING )
458   {
459     bool animationFinished = false;
460
461     if( currentFrame >= endFrame )  // last frame
462     {
463       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
464       {
465         mForward = false;
466       }
467       else
468       {
469         if( loopCount < 0 || ++currentLoopCount < loopCount )   // repeat forever or before the last loop
470         {
471           ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );  // If the current frame is changed in the event thread, don't overwrite it.
472           mUpdateFrameNumber = false;
473         }
474         else
475         {
476           animationFinished = true;   // end of animation
477         }
478         ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
479       }
480     }
481     else if( currentFrame == startFrame && !mForward )  // first frame
482     {
483       if( loopCount < 0 || ++currentLoopCount < loopCount )   // repeat forever or before the last loop
484       {
485         mForward = true;
486       }
487       else
488       {
489         animationFinished = true;   // end of animation
490       }
491       ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
492     }
493
494     if( animationFinished )
495     {
496       if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
497       {
498         stopped = true;
499       }
500       else
501       {
502         mPlayState = PlayState::STOPPING;
503       }
504     }
505   }
506
507   // Rasterize
508   bool renderSuccess = false;
509   if( mVectorRenderer )
510   {
511     renderSuccess = mVectorRenderer.Render( currentFrame );
512     if( !renderSuccess )
513     {
514       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
515       mUpdateFrameNumber = false;
516     }
517   }
518
519   if( stopped && renderSuccess )
520   {
521     mPlayState = PlayState::STOPPED;
522     mForward = true;
523     mCurrentLoop = 0;
524
525     // Animation is finished
526     if( needAnimationFinishedTrigger && mAnimationFinishedTrigger )
527     {
528       mAnimationFinishedTrigger->Trigger();
529     }
530
531     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
532   }
533
534   bool keepAnimation = true;
535   if( playState == PlayState::PAUSED || playState == PlayState::STOPPED )
536   {
537     keepAnimation = false;
538   }
539
540   return keepAnimation;
541 }
542
543 uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
544 {
545   uint32_t frame = currentFrame;
546
547   switch( mStopBehavior )
548   {
549     case DevelImageVisual::StopBehavior::FIRST_FRAME:
550     {
551       frame = startFrame;
552       break;
553     }
554     case DevelImageVisual::StopBehavior::LAST_FRAME:
555     {
556       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
557       {
558         frame = startFrame;
559       }
560       else
561       {
562         frame = endFrame;
563       }
564       break;
565     }
566     case DevelImageVisual::StopBehavior::CURRENT_FRAME:
567     {
568       frame = currentFrame;
569       break;
570     }
571   }
572
573   return frame;
574 }
575
576 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::CalculateNextFrameTime( bool renderNow )
577 {
578   // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported
579   // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
580   // is casted to use the default duration.
581   mNextFrameStartTime =  std::chrono::time_point_cast< std::chrono::time_point< std::chrono::system_clock >::duration >(
582       mNextFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds ) );
583   auto current = std::chrono::system_clock::now();
584   if( renderNow || mNextFrameStartTime < current )
585   {
586     mNextFrameStartTime = current;
587   }
588   return mNextFrameStartTime;
589 }
590
591 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::GetNextFrameTime()
592 {
593   return mNextFrameStartTime;
594 }
595
596 } // namespace Internal
597
598 } // namespace Toolkit
599
600 } // namespace Dali