lottie_single_player.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #include "lottie/lottie_single_player.h"
  8. #include "lottie/details/lottie_frame_renderer.h"
  9. #include "lottie/details/lottie_frame_provider_shared.h"
  10. #include "lottie/details/lottie_frame_provider_direct.h"
  11. #ifdef LOTTIE_USE_CACHE
  12. #include "lottie/details/lottie_frame_provider_cached_multi.h"
  13. #endif // LOTTIE_USE_CACHE
  14. #include <crl/crl_async.h>
  15. namespace Lottie {
  16. SinglePlayer::SinglePlayer(
  17. const QByteArray &content,
  18. const FrameRequest &request,
  19. Quality quality,
  20. const ColorReplacements *replacements,
  21. std::shared_ptr<FrameRenderer> renderer)
  22. : _timer([=] { checkNextFrameRender(); })
  23. , _renderer(renderer ? renderer : FrameRenderer::Instance())
  24. , _animation(this, content, request, quality, replacements) {
  25. }
  26. SinglePlayer::SinglePlayer(
  27. FnMut<void(FnMut<void(QByteArray &&cached)>)> get, // Main thread.
  28. FnMut<void(QByteArray &&cached)> put, // Unknown thread.
  29. const QByteArray &content,
  30. const FrameRequest &request,
  31. Quality quality,
  32. const ColorReplacements *replacements,
  33. std::shared_ptr<FrameRenderer> renderer)
  34. : _timer([=] { checkNextFrameRender(); })
  35. , _renderer(renderer ? renderer : FrameRenderer::Instance())
  36. , _animation(
  37. this,
  38. std::move(get),
  39. std::move(put),
  40. content,
  41. request,
  42. quality,
  43. replacements) {
  44. }
  45. SinglePlayer::SinglePlayer(
  46. int keysCount,
  47. FnMut<void(int, FnMut<void(QByteArray &&)>)> get,
  48. FnMut<void(int, QByteArray &&)> put,
  49. const QByteArray &content,
  50. const FrameRequest &request,
  51. Quality quality,
  52. const ColorReplacements *replacements,
  53. std::shared_ptr<FrameRenderer> renderer)
  54. : _timer([=] { checkNextFrameRender(); })
  55. , _renderer(renderer ? renderer : FrameRenderer::Instance())
  56. , _animation(
  57. this,
  58. keysCount,
  59. std::move(get),
  60. std::move(put),
  61. content,
  62. request,
  63. quality,
  64. replacements) {
  65. }
  66. SinglePlayer::~SinglePlayer() {
  67. if (_state) {
  68. _renderer->remove(_state);
  69. }
  70. }
  71. std::shared_ptr<FrameProvider> SinglePlayer::SharedProvider(
  72. int keysCount,
  73. FnMut<void(int, FnMut<void(QByteArray &&)>)> get,
  74. FnMut<void(int, QByteArray &&)> put,
  75. const QByteArray &content,
  76. const FrameRequest &request,
  77. Quality quality,
  78. const ColorReplacements *replacements) {
  79. auto factory = [=, get = std::move(get), put = std::move(put)](
  80. FnMut<void(std::unique_ptr<FrameProvider>)> done) mutable {
  81. #ifdef LOTTIE_USE_CACHE
  82. struct State {
  83. std::atomic<int> left = 0;
  84. std::vector<QByteArray> caches;
  85. FnMut<void(int, QByteArray &&cached)> put;
  86. FnMut<void(std::unique_ptr<FrameProvider>)> done;
  87. };
  88. const auto state = std::make_shared<State>();
  89. state->left = keysCount;
  90. state->put = std::move(put);
  91. state->done = std::move(done);
  92. state->caches.resize(keysCount);
  93. for (auto i = 0; i != keysCount; ++i) {
  94. get(i, [=](QByteArray &&cached) {
  95. state->caches[i] = std::move(cached);
  96. if (--state->left) {
  97. return;
  98. }
  99. crl::async([=, done = std::move(state->done)]() mutable {
  100. if (const auto error = ContentError(content)) {
  101. done(nullptr);
  102. return;
  103. }
  104. auto provider = std::make_unique<FrameProviderCachedMulti>(
  105. content,
  106. std::move(state->put),
  107. std::move(state->caches),
  108. request,
  109. quality,
  110. replacements);
  111. done(provider->valid() ? std::move(provider) : nullptr);
  112. });
  113. });
  114. }
  115. #else // LOTTIE_USE_CACHE
  116. crl::async([=, done = std::move(done)]() mutable {
  117. if (const auto error = ContentError(content)) {
  118. done(nullptr);
  119. return;
  120. }
  121. auto provider = std::make_unique<FrameProviderDirect>(quality);
  122. done(provider->load(content, replacements)
  123. ? std::move(provider)
  124. : nullptr);
  125. });
  126. #endif // LOTTIE_USE_CACHE
  127. };
  128. return std::make_shared<FrameProviderShared>(std::move(factory));
  129. }
  130. SinglePlayer::SinglePlayer(
  131. std::shared_ptr<FrameProvider> provider,
  132. const FrameRequest &request,
  133. std::shared_ptr<FrameRenderer> renderer)
  134. : _timer([=] { checkNextFrameRender(); })
  135. , _renderer(renderer ? renderer : FrameRenderer::Instance())
  136. , _animation(this, std::move(provider), request) {
  137. }
  138. void SinglePlayer::start(
  139. not_null<Animation*> animation,
  140. std::unique_ptr<SharedState> state) {
  141. Expects(animation == &_animation);
  142. _state = state.get();
  143. auto information = state->information();
  144. state->start(this, crl::now());
  145. const auto request = state->frameForPaint()->request;
  146. _renderer->append(std::move(state), request);
  147. crl::on_main_update_requests(
  148. ) | rpl::start_with_next([=] {
  149. checkStep();
  150. }, _lifetime);
  151. // This may destroy the player.
  152. _updates.fire({ std::move(information) });
  153. }
  154. void SinglePlayer::failed(not_null<Animation*> animation, Error error) {
  155. Expects(animation == &_animation);
  156. _updates.fire_error(std::move(error));
  157. }
  158. rpl::producer<Update, Error> SinglePlayer::updates() const {
  159. return _updates.events();
  160. }
  161. bool SinglePlayer::ready() const {
  162. return _animation.ready();
  163. }
  164. QImage SinglePlayer::frame() const {
  165. return _animation.frame();
  166. }
  167. QImage SinglePlayer::frame(const FrameRequest &request) const {
  168. return _animation.frame(request);
  169. }
  170. Animation::FrameInfo SinglePlayer::frameInfo(
  171. const FrameRequest &request) const {
  172. return _animation.frameInfo(request);
  173. }
  174. int SinglePlayer::frameIndex() const {
  175. return _animation.frameIndex();
  176. }
  177. int SinglePlayer::framesCount() const {
  178. return _animation.framesCount();
  179. }
  180. Information SinglePlayer::information() const {
  181. return _animation.information();
  182. }
  183. void SinglePlayer::checkStep() {
  184. if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
  185. return;
  186. } else if (_nextFrameTime != kTimeUnknown) {
  187. checkNextFrameRender();
  188. } else {
  189. checkNextFrameAvailability();
  190. }
  191. }
  192. void SinglePlayer::checkNextFrameAvailability() {
  193. Expects(_state != nullptr);
  194. Expects(_nextFrameTime == kTimeUnknown);
  195. _nextFrameTime = _state->nextFrameDisplayTime();
  196. Assert(_nextFrameTime != kFrameDisplayTimeAlreadyDone);
  197. if (_nextFrameTime != kTimeUnknown) {
  198. checkNextFrameRender();
  199. }
  200. }
  201. void SinglePlayer::checkNextFrameRender() {
  202. Expects(_nextFrameTime != kTimeUnknown);
  203. const auto now = crl::now();
  204. if (now < _nextFrameTime) {
  205. if (!_timer.isActive()) {
  206. _timer.callOnce(_nextFrameTime - now);
  207. }
  208. } else {
  209. _timer.cancel();
  210. renderFrame(now);
  211. }
  212. }
  213. void SinglePlayer::renderFrame(crl::time now) {
  214. _state->markFrameDisplayed(now);
  215. _state->addTimelineDelay(now - _nextFrameTime);
  216. _nextFrameTime = kFrameDisplayTimeAlreadyDone;
  217. _updates.fire({ DisplayFrameRequest() });
  218. }
  219. void SinglePlayer::updateFrameRequest(
  220. not_null<const Animation*> animation,
  221. const FrameRequest &request) {
  222. Expects(animation == &_animation);
  223. Expects(_state != nullptr);
  224. _renderer->updateFrameRequest(_state, request);
  225. }
  226. bool SinglePlayer::markFrameShown() {
  227. Expects(_state != nullptr);
  228. if (_nextFrameTime == kFrameDisplayTimeAlreadyDone) {
  229. _nextFrameTime = kTimeUnknown;
  230. }
  231. if (_state->markFrameShown()) {
  232. _renderer->frameShown();
  233. return true;
  234. }
  235. return false;
  236. }
  237. } // namespace Lottie