| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #include "lottie/lottie_single_player.h"
- #include "lottie/details/lottie_frame_renderer.h"
- #include "lottie/details/lottie_frame_provider_shared.h"
- #include "lottie/details/lottie_frame_provider_direct.h"
- #ifdef LOTTIE_USE_CACHE
- #include "lottie/details/lottie_frame_provider_cached_multi.h"
- #endif // LOTTIE_USE_CACHE
- #include <crl/crl_async.h>
- namespace Lottie {
- SinglePlayer::SinglePlayer(
- const QByteArray &content,
- const FrameRequest &request,
- Quality quality,
- const ColorReplacements *replacements,
- std::shared_ptr<FrameRenderer> renderer)
- : _timer([=] { checkNextFrameRender(); })
- , _renderer(renderer ? renderer : FrameRenderer::Instance())
- , _animation(this, content, request, quality, replacements) {
- }
- SinglePlayer::SinglePlayer(
- FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
- FnMut<void(QByteArray &&cached)> put, // Unknown thread.
- const QByteArray &content,
- const FrameRequest &request,
- Quality quality,
- const ColorReplacements *replacements,
- std::shared_ptr<FrameRenderer> renderer)
- : _timer([=] { checkNextFrameRender(); })
- , _renderer(renderer ? renderer : FrameRenderer::Instance())
- , _animation(
- this,
- std::move(get),
- std::move(put),
- content,
- request,
- quality,
- replacements) {
- }
- SinglePlayer::SinglePlayer(
- int keysCount,
- FnMut<void(int, FnMut<void(QByteArray &&)>)> get,
- FnMut<void(int, QByteArray &&)> put,
- const QByteArray &content,
- const FrameRequest &request,
- Quality quality,
- const ColorReplacements *replacements,
- std::shared_ptr<FrameRenderer> renderer)
- : _timer([=] { checkNextFrameRender(); })
- , _renderer(renderer ? renderer : FrameRenderer::Instance())
- , _animation(
- this,
- keysCount,
- std::move(get),
- std::move(put),
- content,
- request,
- quality,
- replacements) {
- }
- SinglePlayer::~SinglePlayer() {
- if (_state) {
- _renderer->remove(_state);
- }
- }
- std::shared_ptr<FrameProvider> SinglePlayer::SharedProvider(
- int keysCount,
- FnMut<void(int, FnMut<void(QByteArray &&)>)> get,
- FnMut<void(int, QByteArray &&)> put,
- const QByteArray &content,
- const FrameRequest &request,
- Quality quality,
- const ColorReplacements *replacements) {
- auto factory = [=, get = std::move(get), put = std::move(put)](
- FnMut<void(std::unique_ptr<FrameProvider>)> done) mutable {
- #ifdef LOTTIE_USE_CACHE
- struct State {
- std::atomic<int> left = 0;
- std::vector<QByteArray> caches;
- FnMut<void(int, QByteArray &&cached)> put;
- FnMut<void(std::unique_ptr<FrameProvider>)> done;
- };
- const auto state = std::make_shared<State>();
- state->left = keysCount;
- state->put = std::move(put);
- state->done = std::move(done);
- state->caches.resize(keysCount);
- for (auto i = 0; i != keysCount; ++i) {
- get(i, [=](QByteArray &&cached) {
- state->caches[i] = std::move(cached);
- if (--state->left) {
- return;
- }
- crl::async([=, done = std::move(state->done)]() mutable {
- if (const auto error = ContentError(content)) {
- done(nullptr);
- return;
- }
- auto provider = std::make_unique<FrameProviderCachedMulti>(
- content,
- std::move(state->put),
- std::move(state->caches),
- request,
- quality,
- replacements);
- done(provider->valid() ? std::move(provider) : nullptr);
- });
- });
- }
- #else // LOTTIE_USE_CACHE
- crl::async([=, done = std::move(done)]() mutable {
- if (const auto error = ContentError(content)) {
- done(nullptr);
- return;
- }
- auto provider = std::make_unique<FrameProviderDirect>(quality);
- done(provider->load(content, replacements)
- ? std::move(provider)
- : nullptr);
- });
- #endif // LOTTIE_USE_CACHE
- };
- return std::make_shared<FrameProviderShared>(std::move(factory));
- }
- SinglePlayer::SinglePlayer(
- std::shared_ptr<FrameProvider> provider,
- const FrameRequest &request,
- std::shared_ptr<FrameRenderer> renderer)
- : _timer([=] { checkNextFrameRender(); })
- , _renderer(renderer ? renderer : FrameRenderer::Instance())
- , _animation(this, std::move(provider), request) {
- }
- void SinglePlayer::start(
- not_null<Animation*> animation,
- std::unique_ptr<SharedState> state) {
- Expects(animation == &_animation);
- _state = state.get();
- auto information = state->information();
- state->start(this, crl::now());
- const auto request = state->frameForPaint()->request;
- _renderer->append(std::move(state), request);
- crl::on_main_update_requests(
- ) | rpl::start_with_next([=] {
- checkStep();
- }, _lifetime);
- // This may destroy the player.
- _updates.fire({ std::move(information) });
- }
- void SinglePlayer::failed(not_null<Animation*> animation, Error error) {
- Expects(animation == &_animation);
- _updates.fire_error(std::move(error));
- }
- rpl::producer<Update, Error> SinglePlayer::updates() const {
- return _updates.events();
- }
- bool SinglePlayer::ready() const {
- return _animation.ready();
- }
- QImage SinglePlayer::frame() const {
- return _animation.frame();
- }
- QImage SinglePlayer::frame(const FrameRequest &request) const {
- return _animation.frame(request);
- }
- Animation::FrameInfo SinglePlayer::frameInfo(
- const FrameRequest &request) const {
- return _animation.frameInfo(request);
- }
- int SinglePlayer::frameIndex() const {
- return _animation.frameIndex();
- }
- int SinglePlayer::framesCount() const {
- return _animation.framesCount();
- }
- Information SinglePlayer::information() const {
- return _animation.information();
- }
- void SinglePlayer::checkStep() {
- if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
- return;
- } else if (_nextFrameTime != kTimeUnknown) {
- checkNextFrameRender();
- } else {
- checkNextFrameAvailability();
- }
- }
- void SinglePlayer::checkNextFrameAvailability() {
- Expects(_state != nullptr);
- Expects(_nextFrameTime == kTimeUnknown);
- _nextFrameTime = _state->nextFrameDisplayTime();
- Assert(_nextFrameTime != kFrameDisplayTimeAlreadyDone);
- if (_nextFrameTime != kTimeUnknown) {
- checkNextFrameRender();
- }
- }
- void SinglePlayer::checkNextFrameRender() {
- Expects(_nextFrameTime != kTimeUnknown);
- const auto now = crl::now();
- if (now < _nextFrameTime) {
- if (!_timer.isActive()) {
- _timer.callOnce(_nextFrameTime - now);
- }
- } else {
- _timer.cancel();
- renderFrame(now);
- }
- }
- void SinglePlayer::renderFrame(crl::time now) {
- _state->markFrameDisplayed(now);
- _state->addTimelineDelay(now - _nextFrameTime);
- _nextFrameTime = kFrameDisplayTimeAlreadyDone;
- _updates.fire({ DisplayFrameRequest() });
- }
- void SinglePlayer::updateFrameRequest(
- not_null<const Animation*> animation,
- const FrameRequest &request) {
- Expects(animation == &_animation);
- Expects(_state != nullptr);
- _renderer->updateFrameRequest(_state, request);
- }
- bool SinglePlayer::markFrameShown() {
- Expects(_state != nullptr);
- if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
- _nextFrameTime = kTimeUnknown;
- }
- if (_state->markFrameShown()) {
- _renderer->frameShown();
- return true;
- }
- return false;
- }
- } // namespace Lottie
|