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