1 #include <lottieplayer.h>
3 #include "lottieitem.h"
4 #include "lottieloader.h"
5 #include "lottiemodel.h"
9 using namespace lotplayer;
11 class LOTPlayerPrivate {
15 bool update(float pos);
16 bool setFilePath(std::string path);
17 void setSize(const VSize &sz);
18 void setPos(float pos);
20 float playTime() const;
22 const std::vector<LOTNode *> &renderList(float pos);
23 bool render(float pos, const LOTBuffer &buffer, bool forceRender);
26 std::string mFilePath;
27 std::shared_ptr<LOTModel> mModel;
28 std::unique_ptr<LOTCompItem> mCompItem;
30 std::atomic<bool> mRenderInProgress;
34 void LOTPlayerPrivate::setSize(const VSize &sz)
39 VSize LOTPlayerPrivate::size() const
44 return mCompItem->size();
48 const std::vector<LOTNode *> &LOTPlayerPrivate::renderList(float pos)
51 static std::vector<LOTNode *> empty;
57 return mCompItem->renderList();
60 float LOTPlayerPrivate::playTime() const
62 if (!mModel || mModel->isStatic()) return 0;
63 return float(mModel->frameDuration()) / float(mModel->frameRate());
66 float LOTPlayerPrivate::pos()
71 void LOTPlayerPrivate::setPos(float pos)
73 if (pos > 1.0) pos = 1.0;
78 bool LOTPlayerPrivate::update(float pos)
80 if (!mCompItem) return false;
82 mCompItem->resize(mSize);
86 if (mModel->isStatic()) frameNumber = 0;
87 else frameNumber = mModel->startFrame() + pos() * mModel->frameDuration();
89 return mCompItem->update(frameNumber);
92 bool LOTPlayerPrivate::render(float pos, const LOTBuffer &buffer, bool forceRender)
94 if (!mCompItem) return false;
96 bool renderInProgress = mRenderInProgress.load();
99 vCritical << "Already Rendering Scheduled for this Player";
104 if (update(pos) || forceRender)
106 mRenderInProgress.store(true);
107 result = mCompItem->render(buffer);
108 mRenderInProgress.store(false);
114 LOTPlayerPrivate::LOTPlayerPrivate() : mRenderInProgress(false) {}
116 bool LOTPlayerPrivate::setFilePath(std::string path)
119 vWarning << "File path is empty";
124 if (loader.load(path)) {
125 mModel = loader.model();
126 mCompItem = std::make_unique<LOTCompItem>(mModel.get());
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.
144 RenderTask() { receiver = sender.get_future(); }
145 std::promise<bool> sender;
146 std::future<bool> receiver;
147 LOTPlayerPrivate * playerImpl;
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};
163 RenderTask *task = nullptr;
165 for (unsigned n = 0; n != _count * 32; ++n) {
166 if (_q[(i + n) % _count].try_pop(task)) break;
168 if (!task && !_q[i].pop(task)) break;
170 bool result = task->playerImpl->render(task->pos, task->buffer, task->forceRender);
171 task->sender.set_value(result);
177 RenderTaskScheduler()
179 for (unsigned n = 0; n != _count; ++n) {
180 _threads.emplace_back([&, n] { run(n); });
184 ~RenderTaskScheduler()
186 for (auto &e : _q) e.done();
188 for (auto &e : _threads) e.join();
191 std::future<bool> async(RenderTask *task)
193 auto receiver = std::move(task->receiver);
196 for (unsigned n = 0; n != _count; ++n) {
197 if (_q[(i + n) % _count].try_push(task)) return receiver;
200 _q[i % _count].push(task);
205 std::future<bool> render(LOTPlayerPrivate *impl, float pos,
206 LOTBuffer &&buffer, bool forceRender)
208 RenderTask *task = new RenderTask();
209 task->playerImpl = impl;
211 task->buffer = std::move(buffer);
212 task->forceRender = forceRender;
216 static RenderTaskScheduler render_scheduler;
218 LOTPlayer::LOTPlayer() : d(new LOTPlayerPrivate()) {}
220 LOTPlayer::~LOTPlayer()
226 * \breif Brief abput the Api.
227 * Description about the setFilePath Api
228 * @param path add the details
231 bool LOTPlayer::setFilePath(const char *filePath)
233 return d->setFilePath(filePath);
236 void LOTPlayer::setSize(int width, int height)
238 d->setSize(VSize(width, height));
241 void LOTPlayer::size(int &width, int &height) const
243 VSize sz = d->size();
246 height = sz.height();
249 float LOTPlayer::playTime() const
251 return d->playTime();
254 float LOTPlayer::pos()
259 const std::vector<LOTNode *> &LOTPlayer::renderList(float pos) const
261 return d->renderList(pos);
264 std::future<bool> LOTPlayer::render(float pos, LOTBuffer buffer, bool forceRender)
266 return render_scheduler.render(d, pos, std::move(buffer), forceRender);
269 bool LOTPlayer::renderSync(float pos, LOTBuffer buffer, bool forceRender)
271 return d->render(pos, buffer, forceRender);
276 #if defined(__ARM_NEON__)
277 set_log_level(LogLevel::OFF);
279 initialize(GuaranteedLogger(), "/tmp/", "lotti-player", 1);
280 set_log_level(LogLevel::INFO);
284 V_CONSTRUCTOR_FUNCTION(initLogging)