lottianimation: fix incorrect animation in time stretch.
[platform/core/uifw/lottie-player.git] / src / lottie / lottieanimation.cpp
1 #include "lottieanimation.h"
2
3 #include "lottieitem.h"
4 #include "lottieloader.h"
5 #include "lottiemodel.h"
6
7 #include <fstream>
8
9 using namespace lottie;
10
11 class AnimationImpl {
12
13 public:
14     void    init(const std::shared_ptr<LOTModel> &model);
15     bool    update(size_t frameNo, const VSize &size);
16     VSize   size() const {return mCompItem->size();}
17     double  duration() const {return mModel->duration();}
18     double  frameRate() const {return mModel->frameRate();}
19     size_t  totalFrame() const {return mModel->frameDuration();}
20     size_t  frameAtPos(double pos) const {return mModel->frameAtPos(pos);}
21     Surface render(size_t frameNo, const Surface &surface);
22
23     const std::vector<LOTNode *> &
24                  renderList(size_t frameNo, const VSize &size);
25 private:
26     std::string                  mFilePath;
27     std::shared_ptr<LOTModel>    mModel;
28     std::unique_ptr<LOTCompItem> mCompItem;
29     std::atomic<bool>            mRenderInProgress;
30 };
31
32 const std::vector<LOTNode *> &AnimationImpl::renderList(size_t frameNo, const VSize &size)
33 {
34     if (update(frameNo, size)) {
35        mCompItem->buildRenderList();
36     }
37     return mCompItem->renderList();
38 }
39
40 bool AnimationImpl::update(size_t frameNo, const VSize &size)
41 {
42    frameNo += mModel->startFrame();
43
44    if (frameNo > mModel->endFrame())
45        frameNo = mModel->endFrame();
46
47    if (frameNo < mModel->startFrame())
48        frameNo = mModel->startFrame();
49
50    mCompItem->resize(size);
51    return mCompItem->update(frameNo);
52 }
53
54 Surface AnimationImpl::render(size_t frameNo, const Surface &surface)
55 {
56     bool renderInProgress = mRenderInProgress.load();
57     if (renderInProgress)
58       {
59         vCritical << "Already Rendering Scheduled for this Animation";
60         return surface;
61       }
62
63     mRenderInProgress.store(true);
64     update(frameNo, VSize(surface.width(), surface.height()));
65     mCompItem->render(surface);
66     mRenderInProgress.store(false);
67
68     return surface;
69 }
70
71 void AnimationImpl::init(const std::shared_ptr<LOTModel> &model)
72 {
73     mModel = model;
74     mCompItem = std::make_unique<LOTCompItem>(mModel.get());
75     mRenderInProgress = false;
76 }
77
78 /*
79  * Implement a task stealing schduler to perform render task
80  * As each player draws into its own buffer we can delegate this
81  * task to a slave thread. The scheduler creates a threadpool depending
82  * on the number of cores available in the system and does a simple fair
83  * scheduling by assigning the task in a round-robin fashion. Each thread
84  * in the threadpool has its own queue. once it finishes all the task on its
85  * own queue it goes through rest of the queue and looks for task if it founds
86  * one it steals the task from it and executes. if it couldn't find one then it
87  * just waits for new task on its own queue.
88  */
89 struct RenderTask {
90     RenderTask() { receiver = sender.get_future(); }
91     std::promise<Surface> sender;
92     std::future<Surface>  receiver;
93     AnimationImpl     *playerImpl;
94     size_t              frameNo;
95     Surface            surface;
96 };
97
98 #include <vtaskqueue.h>
99 class RenderTaskScheduler {
100     const unsigned           _count{std::thread::hardware_concurrency()};
101     std::vector<std::thread> _threads;
102     std::vector<TaskQueue<RenderTask>> _q{_count};
103     std::atomic<unsigned>              _index{0};
104
105     void run(unsigned i)
106     {
107         while (true) {
108             RenderTask *task = nullptr;
109
110             for (unsigned n = 0; n != _count * 32; ++n) {
111                 if (_q[(i + n) % _count].try_pop(task)) break;
112             }
113             if (!task && !_q[i].pop(task)) break;
114
115             auto result = task->playerImpl->render(task->frameNo, task->surface);
116             task->sender.set_value(result);
117             delete task;
118         }
119     }
120
121 public:
122     RenderTaskScheduler()
123     {
124         for (unsigned n = 0; n != _count; ++n) {
125             _threads.emplace_back([&, n] { run(n); });
126         }
127     }
128
129     ~RenderTaskScheduler()
130     {
131         for (auto &e : _q) e.done();
132
133         for (auto &e : _threads) e.join();
134     }
135
136     std::future<Surface> async(RenderTask *task)
137     {
138         auto receiver = std::move(task->receiver);
139         auto i = _index++;
140
141         for (unsigned n = 0; n != _count; ++n) {
142             if (_q[(i + n) % _count].try_push(task)) return receiver;
143         }
144
145         _q[i % _count].push(task);
146
147         return receiver;
148     }
149
150     std::future<Surface> render(AnimationImpl *impl, size_t frameNo,
151                              Surface &&surface)
152     {
153         RenderTask *task = new RenderTask();
154         task->playerImpl = impl;
155         task->frameNo = frameNo;
156         task->surface = std::move(surface);
157         return async(task);
158     }
159 };
160 static RenderTaskScheduler render_scheduler;
161
162 /**
163  * \breif Brief abput the Api.
164  * Description about the setFilePath Api
165  * @param path  add the details
166  */
167 std::unique_ptr<Animation>
168 Animation::loadFromData(std::string jsonData, const std::string &key)
169 {
170     if (jsonData.empty()) {
171         vWarning << "jason data is empty";
172         return nullptr;
173     }
174
175     LottieLoader loader;
176     if (loader.loadFromData(std::move(jsonData), key)) {
177         auto animation = std::unique_ptr<Animation>(new Animation);
178         animation->d->init(loader.model());
179         return animation;
180     }
181     return nullptr;
182 }
183
184 std::unique_ptr<Animation>
185 Animation::loadFromFile(const std::string &path)
186 {
187     if (path.empty()) {
188         vWarning << "File path is empty";
189         return nullptr;
190     }
191
192     LottieLoader loader;
193     if (loader.load(path)) {
194         auto animation = std::unique_ptr<Animation>(new Animation);
195         animation->d->init(loader.model());
196         return animation;
197     }
198     return nullptr;
199 }
200
201 void Animation::size(size_t &width, size_t &height) const
202 {
203     VSize sz = d->size();
204
205     width = sz.width();
206     height = sz.height();
207 }
208
209 double Animation::duration() const
210 {
211     return d->duration();
212 }
213
214 double Animation::frameRate() const
215 {
216     return d->frameRate();
217 }
218
219 size_t Animation::totalFrame() const
220 {
221     return d->totalFrame();
222 }
223
224 size_t Animation::frameAtPos(double pos)
225 {
226     return d->frameAtPos(pos);
227 }
228
229 const std::vector<LOTNode *> &
230 Animation::renderList(size_t frameNo, size_t width, size_t height) const
231 {
232     return d->renderList(frameNo, VSize(width, height));
233 }
234
235 std::future<Surface> Animation::render(size_t frameNo, Surface surface)
236 {
237     return render_scheduler.render(d.get(), frameNo, std::move(surface));
238 }
239
240 void Animation::renderSync(size_t frameNo, Surface surface)
241 {
242     d->render(frameNo, surface);
243 }
244
245 Animation::Animation(): d(std::make_unique<AnimationImpl>()) {}
246
247 /*
248  * this is only to supress build fail
249  * because unique_ptr expects the destructor in the same translation unit.
250  */
251 Animation::~Animation(){}
252
253 Surface::Surface(uint32_t *buffer,
254                  size_t width, size_t height, size_t bytesPerLine)
255                 :mBuffer(buffer),
256                  mWidth(width),
257                  mHeight(height),
258                  mBytesPerLine(bytesPerLine) {}
259
260
261 void initLogging()
262 {
263 #if defined(__ARM_NEON__)
264     set_log_level(LogLevel::OFF);
265 #else
266     initialize(GuaranteedLogger(), "/tmp/", "lotti-player", 1);
267     set_log_level(LogLevel::INFO);
268 #endif
269 }
270
271 V_CONSTRUCTOR_FUNCTION(initLogging)