f1feb6fdc01553cf49ddcbcee294a32142256451
[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 #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   mForceRender( false )
89 {
90   Initialize();
91 }
92
93 VectorAnimationTask::~VectorAnimationTask()
94 {
95   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::~VectorAnimationTask: destructor [%p]\n", this );
96 }
97
98 void VectorAnimationTask::Finalize()
99 {
100   ConditionalWait::ScopedLock lock( mConditionalWait );
101
102   // Release some objects in the main thread
103   if( mAnimationFinishedTrigger )
104   {
105     mAnimationFinishedTrigger.reset();
106   }
107
108   mVectorRenderer.Finalize();
109 }
110
111 void VectorAnimationTask::SetRenderer( Renderer renderer )
112 {
113   ConditionalWait::ScopedLock lock( mConditionalWait );
114
115   mVectorRenderer.SetRenderer( renderer );
116
117   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetRenderer [%p]\n", this );
118 }
119
120 void VectorAnimationTask::SetAnimationData( const AnimationData& data )
121 {
122   ConditionalWait::ScopedLock lock( mConditionalWait );
123
124   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetAnimationData [%p]\n", this );
125
126   if( data.resendFlag & VectorAnimationTask::RESEND_LOOP_COUNT )
127   {
128     SetLoopCount( data.loopCount );
129   }
130
131   if( data.resendFlag & VectorAnimationTask::RESEND_PLAY_RANGE )
132   {
133     SetPlayRange( data.playRange );
134   }
135
136   if( data.resendFlag & VectorAnimationTask::RESEND_STOP_BEHAVIOR )
137   {
138     SetStopBehavior( data.stopBehavior );
139   }
140
141   if( data.resendFlag & VectorAnimationTask::RESEND_LOOPING_MODE )
142   {
143     SetLoopingMode( data.loopingMode );
144   }
145
146   if( data.resendFlag & VectorAnimationTask::RESEND_CURRENT_FRAME )
147   {
148     SetCurrentFrameNumber( data.currentFrame );
149   }
150
151   if( data.resendFlag & VectorAnimationTask::RESEND_SIZE )
152   {
153     SetSize( data.width, data.height );
154   }
155
156   if( data.resendFlag & VectorAnimationTask::RESEND_PLAY_STATE )
157   {
158     if( data.playState == DevelImageVisual::PlayState::PLAYING )
159     {
160       PlayAnimation();
161     }
162     else if( data.playState == DevelImageVisual::PlayState::PAUSED )
163     {
164       PauseAnimation();
165       RenderFrame();
166     }
167     else if( data.playState == DevelImageVisual::PlayState::STOPPED )
168     {
169       StopAnimation();
170     }
171   }
172   else
173   {
174     if( mPlayState == PlayState::PAUSED || mPlayState == PlayState::STOPPED )
175     {
176       RenderFrame();
177     }
178   }
179 }
180
181 void VectorAnimationTask::SetSize( uint32_t width, uint32_t height )
182 {
183   if( mWidth != width || mHeight != height )
184   {
185     mVectorRenderer.SetSize( width, height );
186
187     mWidth = width;
188     mHeight = height;
189
190     mResourceReady = false;
191
192     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetSize: width = %d, height = %d [%p]\n", width, height, this );
193   }
194 }
195
196 void VectorAnimationTask::PlayAnimation()
197 {
198   if( mPlayState != PlayState::PLAYING )
199   {
200     mUpdateFrameNumber = false;
201     mPlayState = PlayState::PLAYING;
202
203     mVectorAnimationThread.AddTask( this );
204
205     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PlayAnimation: Play [%p]\n", this );
206   }
207 }
208
209 void VectorAnimationTask::StopAnimation()
210 {
211   if( mPlayState != PlayState::STOPPED && mPlayState != PlayState::STOPPING )
212   {
213     mNeedAnimationFinishedTrigger = false;
214     mPlayState = PlayState::STOPPING;
215
216     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::StopAnimation: Stop [%p]\n", this );
217   }
218 }
219
220 void VectorAnimationTask::PauseAnimation()
221 {
222   if( mPlayState == PlayState::PLAYING )
223   {
224     mPlayState = PlayState::PAUSED;
225
226     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::PauseAnimation: Pause [%p]\n", this );
227   }
228 }
229
230 void VectorAnimationTask::RenderFrame()
231 {
232   if( !mResourceReady )
233   {
234     mVectorAnimationThread.AddTask( this );
235
236     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::RenderFrame: Render [%p]\n", this );
237   }
238 }
239
240 void VectorAnimationTask::SetAnimationFinishedCallback( EventThreadCallback* callback )
241 {
242   ConditionalWait::ScopedLock lock( mConditionalWait );
243   if( callback )
244   {
245     mAnimationFinishedTrigger = std::unique_ptr< EventThreadCallback >( callback );
246   }
247 }
248
249 void VectorAnimationTask::SetLoopCount( int32_t count )
250 {
251   if( mLoopCount != count )
252   {
253     mLoopCount = count;
254     mCurrentLoop = 0;
255     mCurrentLoopUpdated = true;
256
257     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopCount: [%d] [%p]\n", count, this );
258   }
259 }
260
261 void VectorAnimationTask::SetPlayRange( const Property::Array& playRange )
262 {
263   bool valid = false;
264   uint32_t startFrame = 0, endFrame = 0;
265   size_t count = playRange.Count();
266
267   if( count >= 2 )
268   {
269     int32_t start = 0, end = 0;
270     if( playRange.GetElementAt( 0 ).Get( start ) && playRange.GetElementAt( 1 ).Get( end ) )
271     {
272       startFrame = static_cast< uint32_t >( start );
273       endFrame = static_cast< uint32_t >( end );
274       valid = true;
275     }
276     else
277     {
278       std::string startMarker, endMarker;
279       if( playRange.GetElementAt( 0 ).Get( startMarker ) && playRange.GetElementAt( 1 ).Get( endMarker ) )
280       {
281         if( mVectorRenderer )
282         {
283           uint32_t frame;   // We don't use this later
284           if( mVectorRenderer.GetMarkerInfo( startMarker, startFrame, frame ) && mVectorRenderer.GetMarkerInfo( endMarker, frame, endFrame ) )
285           {
286             valid = true;
287           }
288         }
289       }
290     }
291   }
292   else if( count == 1 )
293   {
294     std::string marker;
295     if( playRange.GetElementAt( 0 ).Get( marker ) )
296     {
297       if( mVectorRenderer )
298       {
299         mVectorRenderer.GetMarkerInfo( marker, startFrame, endFrame );
300         valid = true;
301       }
302     }
303   }
304
305   if( !valid )
306   {
307     DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range [%p]\n", this );
308     return;
309   }
310
311   // Make sure the range specified is between 0 and the total frame number
312   if( startFrame < mTotalFrame && endFrame < mTotalFrame )
313   {
314     // If the range is not in order swap values
315     if( startFrame > endFrame )
316     {
317       uint32_t temp = startFrame;
318       startFrame = endFrame;
319       endFrame = temp;
320     }
321
322     if( startFrame != mStartFrame || endFrame != mEndFrame )
323     {
324       mStartFrame = startFrame;
325       mEndFrame = endFrame;
326
327       // If the current frame is out of the range, change the current frame also.
328       if( mStartFrame > mCurrentFrame )
329       {
330         mCurrentFrame = mStartFrame;
331
332         mCurrentFrameUpdated = true;
333         mResourceReady = false;
334       }
335       else if( mEndFrame < mCurrentFrame )
336       {
337         mCurrentFrame = mEndFrame;
338
339         mCurrentFrameUpdated = true;
340         mResourceReady = false;
341       }
342
343       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetPlayRange: [%d, %d] [%p]\n", mStartFrame, mEndFrame, this );
344     }
345   }
346   else
347   {
348     DALI_LOG_ERROR( "VectorAnimationTask::SetPlayRange: Invalid range (%d, %d) [%p]\n", startFrame, endFrame, this );
349     return;
350   }
351 }
352
353 void VectorAnimationTask::GetPlayRange( uint32_t& startFrame, uint32_t& endFrame )
354 {
355   startFrame = mStartFrame;
356   endFrame = mEndFrame;
357 }
358
359 DevelImageVisual::PlayState::Type VectorAnimationTask::GetPlayState() const
360 {
361   DevelImageVisual::PlayState::Type state = DevelImageVisual::PlayState::STOPPED;
362
363   switch( mPlayState )
364   {
365     case PlayState::PLAYING:
366     {
367       state = DevelImageVisual::PlayState::PLAYING;
368       break;
369     }
370     case PlayState::PAUSED:
371     {
372       state = DevelImageVisual::PlayState::PAUSED;
373       break;
374     }
375     case PlayState::STOPPING:
376     case PlayState::STOPPED:
377     {
378       state = DevelImageVisual::PlayState::STOPPED;
379       break;
380     }
381   }
382
383   return state;
384 }
385
386 void VectorAnimationTask::SetCurrentFrameNumber( uint32_t frameNumber )
387 {
388   if( mCurrentFrame == frameNumber )
389   {
390     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: Set same frame [%d] [%p]\n", frameNumber, this );
391     return;
392   }
393
394   if( frameNumber >= mStartFrame && frameNumber <= mEndFrame )
395   {
396     mCurrentFrame = frameNumber;
397     mCurrentFrameUpdated = true;
398
399     mUpdateFrameNumber = false;
400     mResourceReady = false;
401
402     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetCurrentFrameNumber: frame number = %d [%p]\n", mCurrentFrame, this );
403   }
404   else
405   {
406     DALI_LOG_ERROR( "Invalid frame number [%d (%d, %d)]\n", frameNumber, mStartFrame, mEndFrame );
407   }
408 }
409
410 uint32_t VectorAnimationTask::GetCurrentFrameNumber() const
411 {
412   return mCurrentFrame;
413 }
414
415 uint32_t VectorAnimationTask::GetTotalFrameNumber() const
416 {
417   return mTotalFrame;
418 }
419
420 void VectorAnimationTask::GetDefaultSize( uint32_t& width, uint32_t& height ) const
421 {
422   mVectorRenderer.GetDefaultSize( width, height );
423 }
424
425 void VectorAnimationTask::SetStopBehavior( DevelImageVisual::StopBehavior::Type stopBehavior )
426 {
427   mStopBehavior = stopBehavior;
428
429   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetStopBehavior: stop behavor = %d [%p]\n", mStopBehavior, this );
430 }
431
432 void VectorAnimationTask::SetLoopingMode( DevelImageVisual::LoopingMode::Type loopingMode )
433 {
434   mLoopingMode = loopingMode;
435
436   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::SetLoopingMode: looping mode = %d [%p]\n", mLoopingMode, this );
437 }
438
439 void VectorAnimationTask::GetLayerInfo( Property::Map& map ) const
440 {
441   mVectorRenderer.GetLayerInfo( map );
442 }
443
444 VectorAnimationTask::UploadCompletedSignalType& VectorAnimationTask::UploadCompletedSignal()
445 {
446   return mVectorRenderer.UploadCompletedSignal();
447 }
448
449 void VectorAnimationTask::Initialize()
450 {
451   mVectorRenderer = VectorAnimationRenderer::New( mUrl );
452
453   mTotalFrame = mVectorRenderer.GetTotalFrameNumber();
454
455   mEndFrame = mTotalFrame - 1;
456
457   mFrameRate = mVectorRenderer.GetFrameRate();
458   mFrameDurationNanoSeconds = NANOSECONDS_PER_SECOND / mFrameRate;
459
460   uint32_t width, height;
461   mVectorRenderer.GetDefaultSize( width, height );
462
463   SetSize( width, height );
464
465   DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Initialize: file = %s [%d frames, %f fps] [%p]\n", mUrl.c_str(), mTotalFrame, mFrameRate, this );
466 }
467
468 bool VectorAnimationTask::Rasterize()
469 {
470   bool stopped = false, needAnimationFinishedTrigger, resourceReady;
471   uint32_t currentFrame, startFrame, endFrame;
472   int32_t loopCount, currentLoopCount;
473   PlayState playState;
474
475   {
476     ConditionalWait::ScopedLock lock( mConditionalWait );
477
478     if( mPlayState == PlayState::PLAYING && mUpdateFrameNumber )
479     {
480       mCurrentFrame = mForward ? mCurrentFrame + 1 : mCurrentFrame - 1;
481       Dali::ClampInPlace( mCurrentFrame, mStartFrame, mEndFrame );
482     }
483
484     currentFrame = mCurrentFrame;
485     startFrame = mStartFrame;
486     endFrame = mEndFrame;
487     loopCount = mLoopCount;
488     currentLoopCount = mCurrentLoop;
489     needAnimationFinishedTrigger = mNeedAnimationFinishedTrigger;
490     playState = mPlayState;
491     resourceReady = mResourceReady;
492
493     mResourceReady = true;
494     mCurrentFrameUpdated = false;
495     mCurrentLoopUpdated = false;
496     mUpdateFrameNumber = true;
497     mNeedAnimationFinishedTrigger = true;
498   }
499
500   if( playState == PlayState::STOPPING )
501   {
502     currentFrame = GetStoppedFrame( startFrame, endFrame, currentFrame );
503     ResetValue( mCurrentFrameUpdated, mCurrentFrame, currentFrame, mConditionalWait );
504
505     stopped = true;
506   }
507   else if( playState == PlayState::PLAYING )
508   {
509     bool animationFinished = false;
510
511     if( currentFrame >= endFrame )  // last frame
512     {
513       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
514       {
515         mForward = false;
516       }
517       else
518       {
519         if( loopCount < 0 || ++currentLoopCount < loopCount )   // repeat forever or before the last loop
520         {
521           ResetValue( mCurrentFrameUpdated, mCurrentFrame, startFrame, mConditionalWait );  // If the current frame is changed in the event thread, don't overwrite it.
522           mUpdateFrameNumber = false;
523         }
524         else
525         {
526           animationFinished = true;   // end of animation
527         }
528         ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
529       }
530     }
531     else if( currentFrame == startFrame && !mForward )  // first frame
532     {
533       if( loopCount < 0 || ++currentLoopCount < loopCount )   // repeat forever or before the last loop
534       {
535         mForward = true;
536       }
537       else
538       {
539         animationFinished = true;   // end of animation
540       }
541       ResetValue( mCurrentLoopUpdated, mCurrentLoop, currentLoopCount, mConditionalWait );
542     }
543
544     if( animationFinished )
545     {
546       if( mStopBehavior == DevelImageVisual::StopBehavior::CURRENT_FRAME )
547       {
548         stopped = true;
549       }
550       else
551       {
552         mPlayState = PlayState::STOPPING;
553       }
554     }
555   }
556
557   // Rasterize
558   bool renderSuccess = false;
559   if( mVectorRenderer )
560   {
561     renderSuccess = mVectorRenderer.Render( currentFrame );
562     if( !renderSuccess )
563     {
564       DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Rendering failed. Try again later.[%d] [%p]\n", currentFrame, this );
565
566       if( mForceRender )
567       {
568         // Ignore previous frames and retry
569         mVectorRenderer.IgnoreRenderedFrames();
570         renderSuccess = mVectorRenderer.Render( currentFrame );
571         mForceRender = false;
572       }
573       else
574       {
575         mForceRender = true;
576       }
577
578       if( !renderSuccess )
579       {
580         mUpdateFrameNumber = false;
581         if( !resourceReady )
582         {
583           ConditionalWait::ScopedLock lock( mConditionalWait );
584           mResourceReady = false;
585         }
586       }
587     }
588     else
589     {
590       mForceRender = false;
591     }
592   }
593
594   if( stopped && renderSuccess )
595   {
596     ConditionalWait::ScopedLock lock( mConditionalWait );
597
598     mPlayState = PlayState::STOPPED;
599     mForward = true;
600     mCurrentLoop = 0;
601
602     // Animation is finished
603     if( needAnimationFinishedTrigger && mAnimationFinishedTrigger )
604     {
605       mAnimationFinishedTrigger->Trigger();
606     }
607
608     DALI_LOG_INFO( gVectorAnimationLogFilter, Debug::Verbose, "VectorAnimationTask::Rasterize: Animation is finished [current = %d] [%p]\n", currentFrame, this );
609   }
610
611   bool keepAnimation = true;
612   if( playState == PlayState::PAUSED || playState == PlayState::STOPPED )
613   {
614     keepAnimation = false;
615   }
616
617   return keepAnimation;
618 }
619
620 uint32_t VectorAnimationTask::GetStoppedFrame( uint32_t startFrame, uint32_t endFrame, uint32_t currentFrame )
621 {
622   uint32_t frame = currentFrame;
623
624   switch( mStopBehavior )
625   {
626     case DevelImageVisual::StopBehavior::FIRST_FRAME:
627     {
628       frame = startFrame;
629       break;
630     }
631     case DevelImageVisual::StopBehavior::LAST_FRAME:
632     {
633       if( mLoopingMode == DevelImageVisual::LoopingMode::AUTO_REVERSE )
634       {
635         frame = startFrame;
636       }
637       else
638       {
639         frame = endFrame;
640       }
641       break;
642     }
643     case DevelImageVisual::StopBehavior::CURRENT_FRAME:
644     {
645       frame = currentFrame;
646       break;
647     }
648   }
649
650   return frame;
651 }
652
653 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::CalculateNextFrameTime( bool renderNow )
654 {
655   // std::chrono::time_point template has second parameter duration which defaults to the std::chrono::system_clock supported
656   // duration. In some C++11 implementations it is a milliseconds duration, so it fails to compile unless mNextFrameStartTime
657   // is casted to use the default duration.
658   mNextFrameStartTime =  std::chrono::time_point_cast< std::chrono::time_point< std::chrono::system_clock >::duration >(
659       mNextFrameStartTime + std::chrono::nanoseconds( mFrameDurationNanoSeconds ) );
660   auto current = std::chrono::system_clock::now();
661   if( renderNow || mNextFrameStartTime < current )
662   {
663     mNextFrameStartTime = current;
664   }
665   return mNextFrameStartTime;
666 }
667
668 std::chrono::time_point< std::chrono::system_clock > VectorAnimationTask::GetNextFrameTime()
669 {
670   return mNextFrameStartTime;
671 }
672
673 } // namespace Internal
674
675 } // namespace Toolkit
676
677 } // namespace Dali