2019-02-17 11:08:29 +00:00
|
|
|
/*
|
|
|
|
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 14:01:11 +00:00
|
|
|
constexpr auto kFrameDisplayTimeAlreadyDone
|
|
|
|
= std::numeric_limits<crl::time>::max();
|
|
|
|
|
2019-02-17 11:08:29 +00:00
|
|
|
class VideoTrackObject;
|
2019-12-12 06:56:08 +00:00
|
|
|
class Instance;
|
2019-02-17 11:08:29 +00:00
|
|
|
|
|
|
|
class VideoTrack final {
|
|
|
|
public:
|
|
|
|
// Called from some unspecified thread.
|
|
|
|
// Callbacks are assumed to be thread-safe.
|
|
|
|
VideoTrack(
|
2019-02-21 09:17:25 +00:00
|
|
|
const PlaybackOptions &options,
|
2019-02-17 11:08:29 +00:00
|
|
|
Stream &&stream,
|
2019-02-21 11:15:44 +00:00
|
|
|
const AudioMsgId &audioId,
|
2019-02-17 11:08:29 +00:00
|
|
|
FnMut<void(const Information &)> ready,
|
2019-03-05 13:56:27 +00:00
|
|
|
Fn<void(Error)> error);
|
2019-02-17 11:08:29 +00:00
|
|
|
|
|
|
|
// Thread-safe.
|
|
|
|
[[nodiscard]] int streamIndex() const;
|
|
|
|
[[nodiscard]] AVRational streamTimeBase() const;
|
2019-03-05 07:40:25 +00:00
|
|
|
[[nodiscard]] crl::time streamDuration() const;
|
2019-02-17 11:08:29 +00:00
|
|
|
|
|
|
|
// Called from the same unspecified thread.
|
2019-12-19 15:14:05 +00:00
|
|
|
void process(std::vector<FFmpeg::Packet> &&packets);
|
2019-02-21 13:40:09 +00:00
|
|
|
void waitForData();
|
2019-02-17 11:08:29 +00:00
|
|
|
|
|
|
|
// Called from the main thread.
|
2019-02-21 14:57:00 +00: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 16:01:55 +00:00
|
|
|
void setSpeed(float64 speed);
|
2019-12-19 10:50:33 +00:00
|
|
|
void setWaitForMarkAsShown(bool wait);
|
2019-02-21 16:01:55 +00:00
|
|
|
|
|
|
|
// Called from the main thread.
|
2019-02-20 13:28:48 +00:00
|
|
|
// Returns the position of the displayed frame.
|
|
|
|
[[nodiscard]] crl::time markFrameDisplayed(crl::time now);
|
2019-12-11 14:01:11 +00:00
|
|
|
void addTimelineDelay(crl::time delayed);
|
|
|
|
bool markFrameShown();
|
2019-03-07 13:23:19 +00:00
|
|
|
[[nodiscard]] crl::time nextFrameDisplayTime() const;
|
2019-12-12 06:56:08 +00:00
|
|
|
[[nodiscard]] QImage frame(
|
|
|
|
const FrameRequest &request,
|
|
|
|
const Instance *instance);
|
|
|
|
void unregisterInstance(not_null<const Instance*> instance);
|
2019-03-07 13:23:19 +00:00
|
|
|
[[nodiscard]] rpl::producer<> checkNextFrame() const;
|
2019-02-22 14:28:10 +00:00
|
|
|
[[nodiscard]] rpl::producer<> waitingForData() const;
|
2019-02-17 11:08:29 +00:00
|
|
|
|
|
|
|
// Called from the main thread.
|
|
|
|
~VideoTrack();
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class VideoTrackObject;
|
|
|
|
|
2019-12-12 06:56:08 +00:00
|
|
|
struct Prepared {
|
|
|
|
Prepared(const FrameRequest &request) : request(request) {
|
|
|
|
}
|
|
|
|
|
|
|
|
FrameRequest request = FrameRequest::NonStrict();
|
|
|
|
QImage image;
|
|
|
|
};
|
2019-02-17 11:08:29 +00:00
|
|
|
struct Frame {
|
2019-06-26 15:04:38 +00:00
|
|
|
FFmpeg::FramePointer decoded = FFmpeg::MakeFramePointer();
|
2019-02-17 11:08:29 +00:00
|
|
|
QImage original;
|
|
|
|
crl::time position = kTimeUnknown;
|
|
|
|
crl::time displayed = kTimeUnknown;
|
2019-03-07 13:23:19 +00:00
|
|
|
crl::time display = kTimeUnknown;
|
2019-02-17 11:08:29 +00:00
|
|
|
|
2019-12-12 06:56:08 +00:00
|
|
|
base::flat_map<const Instance*, Prepared> prepared;
|
2019-02-17 11:08:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class Shared {
|
|
|
|
public:
|
|
|
|
using PrepareFrame = not_null<Frame*>;
|
|
|
|
using PrepareNextCheck = crl::time;
|
|
|
|
using PrepareState = base::optional_variant<
|
|
|
|
PrepareFrame,
|
|
|
|
PrepareNextCheck>;
|
|
|
|
struct PresentFrame {
|
2019-02-20 13:28:48 +00:00
|
|
|
crl::time displayPosition = kTimeUnknown;
|
2019-02-17 11:08:29 +00:00
|
|
|
crl::time nextCheckDelay = 0;
|
2019-12-11 14:01:11 +00:00
|
|
|
crl::time addedWorldTimeDelay = 0;
|
2019-02-17 11:08:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Called from the wrapped object queue.
|
|
|
|
void init(QImage &&cover, crl::time position);
|
|
|
|
[[nodiscard]] bool initialized() const;
|
|
|
|
|
2019-02-27 11:36:19 +00:00
|
|
|
[[nodiscard]] PrepareState prepareState(
|
|
|
|
crl::time trackTime,
|
|
|
|
bool dropStaleFrames);
|
|
|
|
|
2019-03-06 13:00:03 +00:00
|
|
|
// RasterizeCallback(not_null<Frame*>).
|
|
|
|
template <typename RasterizeCallback>
|
2019-02-27 11:36:19 +00:00
|
|
|
[[nodiscard]] PresentFrame presentFrame(
|
2019-03-07 13:23:19 +00:00
|
|
|
TimePoint trackTime,
|
|
|
|
float64 playbackSpeed,
|
2019-03-06 13:00:03 +00:00
|
|
|
bool dropStaleFrames,
|
|
|
|
RasterizeCallback &&rasterize);
|
2019-03-07 13:23:19 +00:00
|
|
|
[[nodiscard]] bool firstPresentHappened() const;
|
2019-02-17 11:08:29 +00:00
|
|
|
|
|
|
|
// Called from the main thread.
|
2019-02-20 13:28:48 +00:00
|
|
|
// Returns the position of the displayed frame.
|
|
|
|
[[nodiscard]] crl::time markFrameDisplayed(crl::time now);
|
2019-12-11 14:01:11 +00:00
|
|
|
void addTimelineDelay(crl::time delayed);
|
|
|
|
bool markFrameShown();
|
2019-03-07 13:23:19 +00:00
|
|
|
[[nodiscard]] crl::time nextFrameDisplayTime() const;
|
2019-02-17 11:08:29 +00:00
|
|
|
[[nodiscard]] not_null<Frame*> frameForPaint();
|
|
|
|
|
|
|
|
private:
|
|
|
|
[[nodiscard]] not_null<Frame*> getFrame(int index);
|
2019-03-07 13:23:19 +00:00
|
|
|
[[nodiscard]] not_null<const Frame*> getFrame(int index) const;
|
2019-02-17 11:08:29 +00:00
|
|
|
[[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 14:01:11 +00:00
|
|
|
// (_counter % 2) == 1 main thread can write _delay.
|
|
|
|
// (_counter % 2) == 0 crl::queue can read _delay.
|
|
|
|
crl::time _delay = kTimeUnknown;
|
|
|
|
|
2019-02-17 11:08:29 +00:00
|
|
|
};
|
|
|
|
|
2019-12-18 17:15:42 +00:00
|
|
|
static void PrepareFrameByRequests(not_null<Frame*> frame, int rotation);
|
2019-03-13 11:11:54 +00:00
|
|
|
[[nodiscard]] static bool IsDecoded(not_null<const Frame*> frame);
|
|
|
|
[[nodiscard]] static bool IsRasterized(not_null<const Frame*> frame);
|
2019-02-27 11:36:19 +00:00
|
|
|
[[nodiscard]] static bool IsStale(
|
2019-03-13 11:11:54 +00:00
|
|
|
not_null<const Frame*> frame,
|
2019-02-27 11:36:19 +00:00
|
|
|
crl::time trackTime);
|
|
|
|
|
2019-02-17 11:08:29 +00:00
|
|
|
const int _streamIndex = 0;
|
|
|
|
const AVRational _streamTimeBase;
|
2019-03-05 07:40:25 +00:00
|
|
|
const crl::time _streamDuration = 0;
|
2019-12-18 17:15:42 +00:00
|
|
|
const int _streamRotation = 0;
|
2019-03-05 09:00:49 +00:00
|
|
|
//AVRational _streamAspect = kNormalAspect;
|
2019-02-17 11:08:29 +00:00
|
|
|
std::unique_ptr<Shared> _shared;
|
|
|
|
|
|
|
|
using Implementation = VideoTrackObject;
|
|
|
|
crl::object_on_queue<Implementation> _wrapped;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace Streaming
|
|
|
|
} // namespace Media
|