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