| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /*
- 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 "ui/image/image_prepare.h"
- #include <QtCore/QTimer>
- #include <QtCore/QMutex>
- namespace Ui {
- struct PreparedFileInformation;
- } // namespace Ui
- namespace Core {
- class FileLocation;
- } // namespace Core
- namespace Media {
- namespace Clip {
- enum class State {
- Reading,
- Error,
- Finished,
- };
- struct FrameRequest {
- [[nodiscard]] bool valid() const {
- return factor > 0;
- }
- QSize frame;
- QSize outer;
- int factor = 0;
- ImageRoundRadius radius = ImageRoundRadius::None;
- RectParts corners = RectPart::AllCorners;
- QColor colored = QColor(0, 0, 0, 0);
- bool keepAlpha = false;
- };
- // Before ReaderPrivate read the first image and got the original frame size.
- inline constexpr auto kWaitingForDimensionsStep = -3;
- // Before Reader got the original frame size and prepared the frame request.
- inline constexpr auto kWaitingForRequestStep = -2;
- // Before ReaderPrivate got the frame request
- // and started waiting for the 1-2 delay.
- inline constexpr auto kWaitingForFirstFrameStep = -1;
- enum class Notification {
- Reinit,
- Repaint,
- };
- class Manager;
- class ReaderPrivate;
- class Reader {
- public:
- using Callback = Fn<void(Notification)>;
- enum class Mode {
- Gif,
- Video,
- };
- Reader(const Core::FileLocation &location, const QByteArray &data, Callback &&callback);
- Reader(const QString &filepath, Callback &&callback);
- Reader(const QByteArray &data, Callback &&callback);
- // Reader can be already deleted.
- static void SafeCallback(
- Reader *reader,
- int threadIndex,
- Notification notification);
- void start(FrameRequest request);
- struct FrameInfo {
- QImage image;
- int index = 0;
- };
- [[nodiscard]] FrameInfo frameInfo(FrameRequest request, crl::time now);
- [[nodiscard]] QImage current(FrameRequest request, crl::time now) {
- auto result = frameInfo(request, now).image;
- moveToNextFrame();
- return result;
- }
- [[nodiscard]] QImage frameOriginal() const {
- if (const auto frame = frameToShow()) {
- auto result = frame->original;
- result.detach();
- return result;
- }
- return QImage();
- }
- bool moveToNextFrame() {
- return moveToNextShow();
- }
- [[nodiscard]] bool currentDisplayed() const {
- const auto frame = frameToShow();
- return !frame || (frame->displayed.loadAcquire() != 0);
- }
- [[nodiscard]] bool autoPausedGif() const {
- return _autoPausedGif.loadAcquire();
- }
- [[nodiscard]] bool videoPaused() const;
- [[nodiscard]] int threadIndex() const {
- return _threadIndex;
- }
- [[nodiscard]] int width() const;
- [[nodiscard]] int height() const;
- [[nodiscard]] State state() const;
- [[nodiscard]] bool started() const {
- const auto step = _step.loadAcquire();
- return (step == kWaitingForFirstFrameStep) || (step >= 0);
- }
- [[nodiscard]] bool ready() const;
- [[nodiscard]] crl::time getPositionMs() const;
- [[nodiscard]] crl::time getDurationMs() const;
- void pauseResumeVideo();
- void stop();
- void error();
- void finished();
- ~Reader();
- private:
- void init(const Core::FileLocation &location, const QByteArray &data);
- Callback _callback;
- State _state = State::Reading;
- crl::time _durationMs = 0;
- mutable int _width = 0;
- mutable int _height = 0;
- // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3
- mutable QAtomicInt _step = kWaitingForDimensionsStep;
- struct Frame {
- void clear() {
- prepared = QImage();
- preparedColored = QColor(0, 0, 0, 0);
- original = QImage();
- }
- QImage prepared;
- QColor preparedColored = QColor(0, 0, 0, 0);
- QImage original;
- FrameRequest request;
- QAtomicInt displayed = 0;
- int index = 0;
- // Should be counted from the end,
- // so that positionMs <= _durationMs.
- crl::time positionMs = 0;
- };
- mutable Frame _frames[3];
- Frame *frameToShow(int *index = nullptr) const; // 0 means not ready
- Frame *frameToWrite(int *index = nullptr) const; // 0 means not ready
- Frame *frameToWriteNext(bool check, int *index = nullptr) const;
- bool moveToNextShow() const;
- void moveToNextWrite() const;
- QAtomicInt _autoPausedGif = 0;
- QAtomicInt _videoPauseRequest = 0;
- int32 _threadIndex;
- friend class Manager;
- ReaderPrivate *_private = nullptr;
- };
- class ReaderPointer {
- public:
- ReaderPointer(std::nullptr_t = nullptr) {
- }
- explicit ReaderPointer(Reader *pointer) : _pointer(pointer) {
- }
- ReaderPointer(const ReaderPointer &other) = delete;
- ReaderPointer &operator=(const ReaderPointer &other) = delete;
- ReaderPointer(ReaderPointer &&other) : _pointer(base::take(other._pointer)) {
- }
- ReaderPointer &operator=(ReaderPointer &&other) {
- swap(other);
- return *this;
- }
- void swap(ReaderPointer &other) {
- qSwap(_pointer, other._pointer);
- }
- Reader *get() const {
- return valid() ? _pointer : nullptr;
- }
- Reader *operator->() const {
- return get();
- }
- void setBad() {
- reset();
- _pointer = BadPointer;
- }
- void reset() {
- ReaderPointer temp;
- swap(temp);
- }
- bool isBad() const {
- return (_pointer == BadPointer);
- }
- bool valid() const {
- return _pointer && !isBad();
- }
- explicit operator bool() const {
- return valid();
- }
- static inline ReaderPointer Bad() {
- ReaderPointer result;
- result.setBad();
- return result;
- }
- ~ReaderPointer();
- private:
- Reader *_pointer = nullptr;
- static Reader *const BadPointer;
- };
- template <typename ...Args>
- inline ReaderPointer MakeReader(Args&&... args) {
- return ReaderPointer(new Reader(std::forward<Args>(args)...));
- }
- [[nodiscard]] Ui::PreparedFileInformation PrepareForSending(
- const QString &fname,
- const QByteArray &data);
- void Finish();
- } // namespace Clip
- } // namespace Media
|