media_streaming_video_track.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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 "media/streaming/media_streaming_utility.h"
  9. #include <crl/crl_object_on_queue.h>
  10. namespace Media {
  11. namespace Streaming {
  12. constexpr auto kFrameDisplayTimeAlreadyDone
  13. = std::numeric_limits<crl::time>::max();
  14. class VideoTrackObject;
  15. class Instance;
  16. class VideoTrack final {
  17. public:
  18. // Called from some unspecified thread.
  19. // Callbacks are assumed to be thread-safe.
  20. VideoTrack(
  21. const PlaybackOptions &options,
  22. Stream &&stream,
  23. const AudioMsgId &audioId,
  24. FnMut<void(const Information &)> ready,
  25. Fn<void(Error)> error);
  26. // Thread-safe.
  27. [[nodiscard]] int streamIndex() const;
  28. [[nodiscard]] AVRational streamTimeBase() const;
  29. [[nodiscard]] crl::time streamDuration() const;
  30. // Called from the same unspecified thread.
  31. void process(std::vector<FFmpeg::Packet> &&packets);
  32. void waitForData();
  33. // Called from the main thread.
  34. // Must be called after 'ready' was invoked.
  35. void pause(crl::time time);
  36. void resume(crl::time time);
  37. // Called from the main thread.
  38. void setSpeed(float64 speed);
  39. void setWaitForMarkAsShown(bool wait);
  40. // Called from the main thread.
  41. // Returns the position of the displayed frame.
  42. [[nodiscard]] crl::time markFrameDisplayed(crl::time now);
  43. void addTimelineDelay(crl::time delayed);
  44. bool markFrameShown();
  45. [[nodiscard]] crl::time nextFrameDisplayTime() const;
  46. [[nodiscard]] QImage frame(
  47. const FrameRequest &request,
  48. const Instance *instance);
  49. [[nodiscard]] FrameWithInfo frameWithInfo(
  50. const FrameRequest &request,
  51. const Instance *instance);
  52. [[nodiscard]] FrameWithInfo frameWithInfo(const Instance *instance);
  53. [[nodiscard]] QImage currentFrameImage();
  54. void unregisterInstance(not_null<const Instance*> instance);
  55. [[nodiscard]] rpl::producer<> checkNextFrame() const;
  56. [[nodiscard]] rpl::producer<> waitingForData() const;
  57. // Called from the main thread.
  58. ~VideoTrack();
  59. private:
  60. friend class VideoTrackObject;
  61. struct Prepared {
  62. Prepared(const FrameRequest &request) : request(request) {
  63. }
  64. FrameRequest request = FrameRequest::NonStrict();
  65. QImage image;
  66. };
  67. struct Frame {
  68. FFmpeg::FramePointer decoded = FFmpeg::MakeFramePointer();
  69. FFmpeg::FramePointer transferred;
  70. QImage original;
  71. FrameYUV yuv;
  72. crl::time position = kTimeUnknown;
  73. crl::time displayed = kTimeUnknown;
  74. crl::time display = kTimeUnknown;
  75. FrameFormat format = FrameFormat::None;
  76. base::flat_map<const Instance*, Prepared> prepared;
  77. int index = 0;
  78. bool alpha = false;
  79. };
  80. struct FrameWithIndex {
  81. not_null<Frame*> frame;
  82. int index = -1;
  83. };
  84. class Shared {
  85. public:
  86. using PrepareFrame = not_null<Frame*>;
  87. using PrepareNextCheck = crl::time;
  88. using PrepareState = std::variant<
  89. v::null_t,
  90. PrepareFrame,
  91. PrepareNextCheck>;
  92. struct PresentFrame {
  93. crl::time displayPosition = kTimeUnknown;
  94. crl::time nextCheckDelay = 0;
  95. crl::time addedWorldTimeDelay = 0;
  96. };
  97. // Called from the wrapped object queue.
  98. void init(QImage &&cover, bool hasAlpha, crl::time position);
  99. [[nodiscard]] bool initialized() const;
  100. [[nodiscard]] PrepareState prepareState(
  101. crl::time trackTime,
  102. bool dropStaleFrames);
  103. [[nodiscard]] PresentFrame presentFrame(
  104. not_null<VideoTrackObject*> object,
  105. TimePoint trackTime,
  106. float64 playbackSpeed,
  107. bool dropStaleFrames);
  108. [[nodiscard]] bool firstPresentHappened() const;
  109. // Called from the main thread.
  110. // Returns the position of the displayed frame.
  111. [[nodiscard]] crl::time markFrameDisplayed(crl::time now);
  112. void addTimelineDelay(crl::time delayed);
  113. bool markFrameShown();
  114. [[nodiscard]] crl::time nextFrameDisplayTime() const;
  115. [[nodiscard]] not_null<Frame*> frameForPaint();
  116. [[nodiscard]] FrameWithIndex frameForPaintWithIndex();
  117. private:
  118. [[nodiscard]] not_null<Frame*> getFrame(int index);
  119. [[nodiscard]] not_null<const Frame*> getFrame(int index) const;
  120. [[nodiscard]] int counter() const;
  121. static constexpr auto kCounterUninitialized = -1;
  122. std::atomic<int> _counter = kCounterUninitialized;
  123. static constexpr auto kFramesCount = 4;
  124. std::array<Frame, kFramesCount> _frames;
  125. // (_counter % 2) == 1 main thread can write _delay.
  126. // (_counter % 2) == 0 crl::queue can read _delay.
  127. crl::time _delay = kTimeUnknown;
  128. };
  129. static void PrepareFrameByRequests(
  130. not_null<Frame*> frame,
  131. const AVRational &aspect,
  132. int rotation);
  133. [[nodiscard]] static bool IsDecoded(not_null<const Frame*> frame);
  134. [[nodiscard]] static bool IsRasterized(not_null<const Frame*> frame);
  135. [[nodiscard]] static bool IsStale(
  136. not_null<const Frame*> frame,
  137. crl::time trackTime);
  138. [[nodiscard]] QImage frameImage(
  139. not_null<Frame*> frame,
  140. const FrameRequest &request,
  141. const Instance *instance);
  142. const int _streamIndex = 0;
  143. const AVRational _streamTimeBase;
  144. const crl::time _streamDuration = 0;
  145. const int _streamRotation = 0;
  146. const AVRational _streamAspect = FFmpeg::kNormalAspect;
  147. std::unique_ptr<Shared> _shared;
  148. using Implementation = VideoTrackObject;
  149. crl::object_on_queue<Implementation> _wrapped;
  150. };
  151. } // namespace Streaming
  152. } // namespace Media