media_clip_reader.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #pragma once
  8. #include "ui/image/image_prepare.h"
  9. #include <QtCore/QTimer>
  10. #include <QtCore/QMutex>
  11. namespace Ui {
  12. struct PreparedFileInformation;
  13. } // namespace Ui
  14. namespace Core {
  15. class FileLocation;
  16. } // namespace Core
  17. namespace Media {
  18. namespace Clip {
  19. enum class State {
  20. Reading,
  21. Error,
  22. Finished,
  23. };
  24. struct FrameRequest {
  25. [[nodiscard]] bool valid() const {
  26. return factor > 0;
  27. }
  28. QSize frame;
  29. QSize outer;
  30. int factor = 0;
  31. ImageRoundRadius radius = ImageRoundRadius::None;
  32. RectParts corners = RectPart::AllCorners;
  33. QColor colored = QColor(0, 0, 0, 0);
  34. bool keepAlpha = false;
  35. };
  36. // Before ReaderPrivate read the first image and got the original frame size.
  37. inline constexpr auto kWaitingForDimensionsStep = -3;
  38. // Before Reader got the original frame size and prepared the frame request.
  39. inline constexpr auto kWaitingForRequestStep = -2;
  40. // Before ReaderPrivate got the frame request
  41. // and started waiting for the 1-2 delay.
  42. inline constexpr auto kWaitingForFirstFrameStep = -1;
  43. enum class Notification {
  44. Reinit,
  45. Repaint,
  46. };
  47. class Manager;
  48. class ReaderPrivate;
  49. class Reader {
  50. public:
  51. using Callback = Fn<void(Notification)>;
  52. enum class Mode {
  53. Gif,
  54. Video,
  55. };
  56. Reader(const Core::FileLocation &location, const QByteArray &data, Callback &&callback);
  57. Reader(const QString &filepath, Callback &&callback);
  58. Reader(const QByteArray &data, Callback &&callback);
  59. // Reader can be already deleted.
  60. static void SafeCallback(
  61. Reader *reader,
  62. int threadIndex,
  63. Notification notification);
  64. void start(FrameRequest request);
  65. struct FrameInfo {
  66. QImage image;
  67. int index = 0;
  68. };
  69. [[nodiscard]] FrameInfo frameInfo(FrameRequest request, crl::time now);
  70. [[nodiscard]] QImage current(FrameRequest request, crl::time now) {
  71. auto result = frameInfo(request, now).image;
  72. moveToNextFrame();
  73. return result;
  74. }
  75. [[nodiscard]] QImage frameOriginal() const {
  76. if (const auto frame = frameToShow()) {
  77. auto result = frame->original;
  78. result.detach();
  79. return result;
  80. }
  81. return QImage();
  82. }
  83. bool moveToNextFrame() {
  84. return moveToNextShow();
  85. }
  86. [[nodiscard]] bool currentDisplayed() const {
  87. const auto frame = frameToShow();
  88. return !frame || (frame->displayed.loadAcquire() != 0);
  89. }
  90. [[nodiscard]] bool autoPausedGif() const {
  91. return _autoPausedGif.loadAcquire();
  92. }
  93. [[nodiscard]] bool videoPaused() const;
  94. [[nodiscard]] int threadIndex() const {
  95. return _threadIndex;
  96. }
  97. [[nodiscard]] int width() const;
  98. [[nodiscard]] int height() const;
  99. [[nodiscard]] State state() const;
  100. [[nodiscard]] bool started() const {
  101. const auto step = _step.loadAcquire();
  102. return (step == kWaitingForFirstFrameStep) || (step >= 0);
  103. }
  104. [[nodiscard]] bool ready() const;
  105. [[nodiscard]] crl::time getPositionMs() const;
  106. [[nodiscard]] crl::time getDurationMs() const;
  107. void pauseResumeVideo();
  108. void stop();
  109. void error();
  110. void finished();
  111. ~Reader();
  112. private:
  113. void init(const Core::FileLocation &location, const QByteArray &data);
  114. Callback _callback;
  115. State _state = State::Reading;
  116. crl::time _durationMs = 0;
  117. mutable int _width = 0;
  118. mutable int _height = 0;
  119. // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3
  120. mutable QAtomicInt _step = kWaitingForDimensionsStep;
  121. struct Frame {
  122. void clear() {
  123. prepared = QImage();
  124. preparedColored = QColor(0, 0, 0, 0);
  125. original = QImage();
  126. }
  127. QImage prepared;
  128. QColor preparedColored = QColor(0, 0, 0, 0);
  129. QImage original;
  130. FrameRequest request;
  131. QAtomicInt displayed = 0;
  132. int index = 0;
  133. // Should be counted from the end,
  134. // so that positionMs <= _durationMs.
  135. crl::time positionMs = 0;
  136. };
  137. mutable Frame _frames[3];
  138. Frame *frameToShow(int *index = nullptr) const; // 0 means not ready
  139. Frame *frameToWrite(int *index = nullptr) const; // 0 means not ready
  140. Frame *frameToWriteNext(bool check, int *index = nullptr) const;
  141. bool moveToNextShow() const;
  142. void moveToNextWrite() const;
  143. QAtomicInt _autoPausedGif = 0;
  144. QAtomicInt _videoPauseRequest = 0;
  145. int32 _threadIndex;
  146. friend class Manager;
  147. ReaderPrivate *_private = nullptr;
  148. };
  149. class ReaderPointer {
  150. public:
  151. ReaderPointer(std::nullptr_t = nullptr) {
  152. }
  153. explicit ReaderPointer(Reader *pointer) : _pointer(pointer) {
  154. }
  155. ReaderPointer(const ReaderPointer &other) = delete;
  156. ReaderPointer &operator=(const ReaderPointer &other) = delete;
  157. ReaderPointer(ReaderPointer &&other) : _pointer(base::take(other._pointer)) {
  158. }
  159. ReaderPointer &operator=(ReaderPointer &&other) {
  160. swap(other);
  161. return *this;
  162. }
  163. void swap(ReaderPointer &other) {
  164. qSwap(_pointer, other._pointer);
  165. }
  166. Reader *get() const {
  167. return valid() ? _pointer : nullptr;
  168. }
  169. Reader *operator->() const {
  170. return get();
  171. }
  172. void setBad() {
  173. reset();
  174. _pointer = BadPointer;
  175. }
  176. void reset() {
  177. ReaderPointer temp;
  178. swap(temp);
  179. }
  180. bool isBad() const {
  181. return (_pointer == BadPointer);
  182. }
  183. bool valid() const {
  184. return _pointer && !isBad();
  185. }
  186. explicit operator bool() const {
  187. return valid();
  188. }
  189. static inline ReaderPointer Bad() {
  190. ReaderPointer result;
  191. result.setBad();
  192. return result;
  193. }
  194. ~ReaderPointer();
  195. private:
  196. Reader *_pointer = nullptr;
  197. static Reader *const BadPointer;
  198. };
  199. template <typename ...Args>
  200. inline ReaderPointer MakeReader(Args&&... args) {
  201. return ReaderPointer(new Reader(std::forward<Args>(args)...));
  202. }
  203. [[nodiscard]] Ui::PreparedFileInformation PrepareForSending(
  204. const QString &fname,
  205. const QByteArray &data);
  206. void Finish();
  207. } // namespace Clip
  208. } // namespace Media