/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include "base/basic_types.h" #include "base/weak_ptr.h" #include "lottie/lottie_common.h" #include #include #include #include #include namespace rlottie { class Animation; } // namespace rlottie namespace Lottie { // Frame rate can be 1, 2, ... , 29, 30 or 60. inline constexpr auto kNormalFrameRate = 30; inline constexpr auto kMaxFrameRate = 60; inline constexpr auto kMaxSize = 4096; inline constexpr auto kMaxFramesCount = 210; inline constexpr auto kFrameDisplayTimeAlreadyDone = std::numeric_limits::max(); inline constexpr auto kDisplayedInitial = crl::time(-1); class Player; class Cache; struct Frame { QImage original; crl::time displayed = kDisplayedInitial; crl::time display = kTimeUnknown; int index = 0; FrameRequest request; QImage prepared; }; QImage PrepareFrameByRequest( not_null frame, bool useExistingPrepared); class SharedState { public: SharedState( std::unique_ptr animation, const FrameRequest &request, Quality quality); SharedState( const QByteArray &content, const ColorReplacements *replacements, std::unique_ptr animation, std::unique_ptr cache, const FrameRequest &request, Quality quality); void start( not_null owner, crl::time now, crl::time delay = 0, int skippedFrames = 0); [[nodiscard]] Information information() const; [[nodiscard]] bool initialized() const; [[nodiscard]] not_null frameForPaint(); [[nodiscard]] int framesCount() const; [[nodiscard]] crl::time nextFrameDisplayTime() const; void addTimelineDelay(crl::time delayed, int skippedFrames = 0); void markFrameDisplayed(crl::time now); bool markFrameShown(); void renderFrame(QImage &image, const FrameRequest &request, int index); struct RenderResult { bool rendered = false; base::weak_ptr notify; }; [[nodiscard]] RenderResult renderNextFrame(const FrameRequest &request); ~SharedState(); private: static Information CalculateInformation( Quality quality, rlottie::Animation *animation, Cache *cache); void construct(const FrameRequest &request); bool isValid() const; void init(QImage cover, const FrameRequest &request); void renderNextFrame( not_null frame, const FrameRequest &request); [[nodiscard]] crl::time countFrameDisplayTime(int index) const; [[nodiscard]] not_null getFrame(int index); [[nodiscard]] not_null getFrame(int index) const; [[nodiscard]] int counter() const; // crl::queue changes 0,2,4,6 to 1,3,5,7. // main thread changes 1,3,5,7 to 2,4,6,0. static constexpr auto kCounterUninitialized = -1; std::atomic _counter = kCounterUninitialized; static constexpr auto kFramesCount = 4; std::array _frames; base::weak_ptr _owner; crl::time _started = kTimeUnknown; // (_counter % 2) == 1 main thread can write _delay. // (_counter % 2) == 0 crl::queue can read _delay. crl::time _delay = kTimeUnknown; int _frameIndex = 0; int _skippedFrames = 0; const Information _info; const Quality _quality = Quality::Default; const std::unique_ptr _cache; std::unique_ptr _animation; const QByteArray _content; const ColorReplacements *_replacements = nullptr; }; class FrameRendererObject; class FrameRenderer final { public: static std::shared_ptr CreateIndependent(); static std::shared_ptr Instance(); void append( std::unique_ptr entry, const FrameRequest &request); void updateFrameRequest( not_null entry, const FrameRequest &request); void frameShown(); void remove(not_null state); private: using Implementation = FrameRendererObject; crl::object_on_queue _wrapped; }; } // namespace Lottie