tdesktop/Telegram/SourceFiles/media/streaming/media_streaming_video_track.h

183 lines
5.1 KiB
C
Raw Normal View History

/*
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 "media/streaming/media_streaming_utility.h"
#include <crl/crl_object_on_queue.h>
namespace Media {
namespace Streaming {
2019-12-11 15:01:11 +01:00
constexpr auto kFrameDisplayTimeAlreadyDone
= std::numeric_limits<crl::time>::max();
class VideoTrackObject;
class Instance;
class VideoTrack final {
public:
// Called from some unspecified thread.
// Callbacks are assumed to be thread-safe.
VideoTrack(
const PlaybackOptions &options,
Stream &&stream,
2019-02-21 12:15:44 +01:00
const AudioMsgId &audioId,
FnMut<void(const Information &)> ready,
2019-03-05 14:56:27 +01:00
Fn<void(Error)> error);
// Thread-safe.
[[nodiscard]] int streamIndex() const;
[[nodiscard]] AVRational streamTimeBase() const;
[[nodiscard]] crl::time streamDuration() const;
// Called from the same unspecified thread.
void process(std::vector<FFmpeg::Packet> &&packets);
void waitForData();
// Called from the main thread.
2019-02-21 15:57:00 +01:00
// Must be called after 'ready' was invoked.
void pause(crl::time time);
void resume(crl::time time);
// Called from the main thread.
2019-02-21 17:01:55 +01:00
void setSpeed(float64 speed);
2019-12-19 11:50:33 +01:00
void setWaitForMarkAsShown(bool wait);
2019-02-21 17:01:55 +01:00
// Called from the main thread.
// Returns the position of the displayed frame.
[[nodiscard]] crl::time markFrameDisplayed(crl::time now);
2019-12-11 15:01:11 +01:00
void addTimelineDelay(crl::time delayed);
bool markFrameShown();
2019-03-07 14:23:19 +01:00
[[nodiscard]] crl::time nextFrameDisplayTime() const;
[[nodiscard]] QImage frame(
const FrameRequest &request,
const Instance *instance);
[[nodiscard]] FrameWithInfo frameWithInfo(
const FrameRequest &request,
const Instance *instance);
2021-06-03 14:57:48 +02:00
[[nodiscard]] FrameWithInfo frameWithInfo(const Instance *instance);
[[nodiscard]] QImage currentFrameImage();
void unregisterInstance(not_null<const Instance*> instance);
2019-03-07 14:23:19 +01:00
[[nodiscard]] rpl::producer<> checkNextFrame() const;
[[nodiscard]] rpl::producer<> waitingForData() const;
// Called from the main thread.
~VideoTrack();
private:
friend class VideoTrackObject;
struct Prepared {
Prepared(const FrameRequest &request) : request(request) {
}
FrameRequest request = FrameRequest::NonStrict();
QImage image;
};
struct Frame {
2019-06-26 17:04:38 +02:00
FFmpeg::FramePointer decoded = FFmpeg::MakeFramePointer();
QImage original;
2021-06-03 14:57:48 +02:00
FrameYUV420 yuv420;
crl::time position = kTimeUnknown;
crl::time displayed = kTimeUnknown;
2019-03-07 14:23:19 +01:00
crl::time display = kTimeUnknown;
2021-06-03 14:57:48 +02:00
FrameFormat format = FrameFormat::None;
base::flat_map<const Instance*, Prepared> prepared;
2020-02-24 14:48:23 +01:00
int index = 0;
2020-02-24 14:48:23 +01:00
bool alpha = false;
};
2021-06-03 14:57:48 +02:00
struct FrameWithIndex {
not_null<Frame*> frame;
int index = -1;
};
class Shared {
public:
using PrepareFrame = not_null<Frame*>;
using PrepareNextCheck = crl::time;
using PrepareState = std::variant<
v::null_t,
PrepareFrame,
PrepareNextCheck>;
struct PresentFrame {
crl::time displayPosition = kTimeUnknown;
crl::time nextCheckDelay = 0;
2019-12-11 15:01:11 +01:00
crl::time addedWorldTimeDelay = 0;
};
// Called from the wrapped object queue.
void init(QImage &&cover, bool hasAlpha, crl::time position);
[[nodiscard]] bool initialized() const;
2019-02-27 12:36:19 +01:00
[[nodiscard]] PrepareState prepareState(
crl::time trackTime,
bool dropStaleFrames);
[[nodiscard]] PresentFrame presentFrame(
2020-07-17 20:59:25 +02:00
not_null<VideoTrackObject*> object,
2019-03-07 14:23:19 +01:00
TimePoint trackTime,
float64 playbackSpeed,
2020-07-17 20:59:25 +02:00
bool dropStaleFrames);
2019-03-07 14:23:19 +01:00
[[nodiscard]] bool firstPresentHappened() const;
// Called from the main thread.
// Returns the position of the displayed frame.
[[nodiscard]] crl::time markFrameDisplayed(crl::time now);
2019-12-11 15:01:11 +01:00
void addTimelineDelay(crl::time delayed);
bool markFrameShown();
2019-03-07 14:23:19 +01:00
[[nodiscard]] crl::time nextFrameDisplayTime() const;
[[nodiscard]] not_null<Frame*> frameForPaint();
2021-06-03 14:57:48 +02:00
[[nodiscard]] FrameWithIndex frameForPaintWithIndex();
private:
[[nodiscard]] not_null<Frame*> getFrame(int index);
2019-03-07 14:23:19 +01:00
[[nodiscard]] not_null<const Frame*> getFrame(int index) const;
[[nodiscard]] int counter() const;
static constexpr auto kCounterUninitialized = -1;
std::atomic<int> _counter = kCounterUninitialized;
static constexpr auto kFramesCount = 4;
std::array<Frame, kFramesCount> _frames;
2019-12-11 15:01:11 +01:00
// (_counter % 2) == 1 main thread can write _delay.
// (_counter % 2) == 0 crl::queue can read _delay.
crl::time _delay = kTimeUnknown;
};
2019-12-18 18:15:42 +01:00
static void PrepareFrameByRequests(not_null<Frame*> frame, int rotation);
2019-03-13 12:11:54 +01:00
[[nodiscard]] static bool IsDecoded(not_null<const Frame*> frame);
[[nodiscard]] static bool IsRasterized(not_null<const Frame*> frame);
2019-02-27 12:36:19 +01:00
[[nodiscard]] static bool IsStale(
2019-03-13 12:11:54 +01:00
not_null<const Frame*> frame,
2019-02-27 12:36:19 +01:00
crl::time trackTime);
[[nodiscard]] QImage frameImage(
not_null<Frame*> frame,
const FrameRequest &request,
const Instance *instance);
const int _streamIndex = 0;
const AVRational _streamTimeBase;
const crl::time _streamDuration = 0;
2019-12-18 18:15:42 +01:00
const int _streamRotation = 0;
//AVRational _streamAspect = kNormalAspect;
std::unique_ptr<Shared> _shared;
using Implementation = VideoTrackObject;
crl::object_on_queue<Implementation> _wrapped;
};
} // namespace Streaming
} // namespace Media