1 #include "lottieanimation.h"
3 #include "lottieitem.h"
4 #include "lottieloader.h"
5 #include "lottiemodel.h"
9 using namespace lottie;
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);
23 const std::vector<LOTNode *> &
24 renderList(size_t frameNo, const VSize &size);
26 std::string mFilePath;
27 std::shared_ptr<LOTModel> mModel;
28 std::unique_ptr<LOTCompItem> mCompItem;
29 std::atomic<bool> mRenderInProgress;
32 const std::vector<LOTNode *> &AnimationImpl::renderList(size_t frameNo, const VSize &size)
34 if (update(frameNo, size)) {
35 mCompItem->buildRenderList();
37 return mCompItem->renderList();
40 bool AnimationImpl::update(size_t frameNo, const VSize &size)
42 if (frameNo > mModel->endFrame())
43 frameNo = mModel->endFrame();
45 if (frameNo < mModel->startFrame())
46 frameNo = mModel->startFrame();
48 mCompItem->resize(size);
49 return mCompItem->update(frameNo);
52 Surface AnimationImpl::render(size_t frameNo, const Surface &surface)
54 bool renderInProgress = mRenderInProgress.load();
57 vCritical << "Already Rendering Scheduled for this Animation";
61 mRenderInProgress.store(true);
62 update(frameNo, VSize(surface.width(), surface.height()));
63 mCompItem->render(surface);
64 mRenderInProgress.store(false);
69 void AnimationImpl::init(const std::shared_ptr<LOTModel> &model)
72 mCompItem = std::make_unique<LOTCompItem>(mModel.get());
73 mRenderInProgress = false;
77 * Implement a task stealing schduler to perform render task
78 * As each player draws into its own buffer we can delegate this
79 * task to a slave thread. The scheduler creates a threadpool depending
80 * on the number of cores available in the system and does a simple fair
81 * scheduling by assigning the task in a round-robin fashion. Each thread
82 * in the threadpool has its own queue. once it finishes all the task on its
83 * own queue it goes through rest of the queue and looks for task if it founds
84 * one it steals the task from it and executes. if it couldn't find one then it
85 * just waits for new task on its own queue.
88 RenderTask() { receiver = sender.get_future(); }
89 std::promise<Surface> sender;
90 std::future<Surface> receiver;
91 AnimationImpl *playerImpl;
96 #include <vtaskqueue.h>
97 class RenderTaskScheduler {
98 const unsigned _count{std::thread::hardware_concurrency()};
99 std::vector<std::thread> _threads;
100 std::vector<TaskQueue<RenderTask>> _q{_count};
101 std::atomic<unsigned> _index{0};
106 RenderTask *task = nullptr;
108 for (unsigned n = 0; n != _count * 32; ++n) {
109 if (_q[(i + n) % _count].try_pop(task)) break;
111 if (!task && !_q[i].pop(task)) break;
113 auto result = task->playerImpl->render(task->frameNo, task->surface);
114 task->sender.set_value(result);
120 RenderTaskScheduler()
122 for (unsigned n = 0; n != _count; ++n) {
123 _threads.emplace_back([&, n] { run(n); });
127 ~RenderTaskScheduler()
129 for (auto &e : _q) e.done();
131 for (auto &e : _threads) e.join();
134 std::future<Surface> async(RenderTask *task)
136 auto receiver = std::move(task->receiver);
139 for (unsigned n = 0; n != _count; ++n) {
140 if (_q[(i + n) % _count].try_push(task)) return receiver;
143 _q[i % _count].push(task);
148 std::future<Surface> render(AnimationImpl *impl, size_t frameNo,
151 RenderTask *task = new RenderTask();
152 task->playerImpl = impl;
153 task->frameNo = frameNo;
154 task->surface = std::move(surface);
158 static RenderTaskScheduler render_scheduler;
161 * \breif Brief abput the Api.
162 * Description about the setFilePath Api
163 * @param path add the details
165 std::unique_ptr<Animation>
166 Animation::loadFromData(std::string jsonData, const std::string &key)
168 if (jsonData.empty()) {
169 vWarning << "jason data is empty";
174 if (loader.loadFromData(std::move(jsonData), key)) {
175 auto animation = std::unique_ptr<Animation>(new Animation);
176 animation->d->init(loader.model());
182 std::unique_ptr<Animation>
183 Animation::loadFromFile(const std::string &path)
186 vWarning << "File path is empty";
191 if (loader.load(path)) {
192 auto animation = std::unique_ptr<Animation>(new Animation);
193 animation->d->init(loader.model());
199 void Animation::size(size_t &width, size_t &height) const
201 VSize sz = d->size();
204 height = sz.height();
207 double Animation::duration() const
209 return d->duration();
212 double Animation::frameRate() const
214 return d->frameRate();
217 size_t Animation::totalFrame() const
219 return d->totalFrame();
222 size_t Animation::frameAtPos(double pos)
224 return d->frameAtPos(pos);
227 const std::vector<LOTNode *> &
228 Animation::renderList(size_t frameNo, size_t width, size_t height) const
230 return d->renderList(frameNo, VSize(width, height));
233 std::future<Surface> Animation::render(size_t frameNo, Surface surface)
235 return render_scheduler.render(d.get(), frameNo, std::move(surface));
238 void Animation::renderSync(size_t frameNo, Surface surface)
240 d->render(frameNo, surface);
243 Animation::Animation(): d(std::make_unique<AnimationImpl>()) {}
246 * this is only to supress build fail
247 * because unique_ptr expects the destructor in the same translation unit.
249 Animation::~Animation(){}
251 Surface::Surface(uint32_t *buffer,
252 size_t width, size_t height, size_t bytesPerLine)
256 mBytesPerLine(bytesPerLine) {}
261 #if defined(__ARM_NEON__)
262 set_log_level(LogLevel::OFF);
264 initialize(GuaranteedLogger(), "/tmp/", "lotti-player", 1);
265 set_log_level(LogLevel::INFO);
269 V_CONSTRUCTOR_FUNCTION(initLogging)