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