Allow multiple players of the same file.

This commit is contained in:
John Preston 2019-12-10 17:06:22 +03:00
parent 8e8c356659
commit 1243123579
7 changed files with 105 additions and 82 deletions

View File

@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/player/media_player_instance.h" // instance()->play()
#include "media/streaming/media_streaming_loader.h" // unique_ptr<Loader>
#include "media/streaming/media_streaming_reader.h" // make_shared<Reader>
#include "media/streaming/media_streaming_document.h" // make_shared<Document
#include "boxes/abstract_box.h"
#include "passport/passport_form_controller.h"
#include "window/themes/window_theme.h"
@ -171,21 +172,22 @@ rpl::producer<int> PinnedDialogsCountMaxValue(
});
}
template <typename Object>
bool PruneDestroyedAndSet(
base::flat_map<
not_null<DocumentData*>,
std::weak_ptr<::Media::Streaming::Reader>> &readers,
std::weak_ptr<Object>> &objects,
not_null<DocumentData*> document,
const std::shared_ptr<::Media::Streaming::Reader> &reader) {
const std::shared_ptr<Object> &object) {
auto result = false;
for (auto i = begin(readers); i != end(readers);) {
for (auto i = begin(objects); i != end(objects);) {
if (i->first == document) {
(i++)->second = reader;
(i++)->second = object;
result = true;
} else if (i->second.lock() != nullptr) {
++i;
} else {
i = readers.erase(i);
i = objects.erase(i);
}
}
return result;
@ -1156,6 +1158,24 @@ std::shared_ptr<::Media::Streaming::Reader> Session::documentStreamedReader(
return result;
}
std::shared_ptr<::Media::Streaming::Document> Session::documentStreamer(
not_null<DocumentData*> document,
FileOrigin origin) {
const auto i = _streamedDocuments.find(document);
if (i != end(_streamedDocuments)) {
if (auto result = i->second.lock()) {
return result;
}
}
auto result = std::make_shared<::Media::Streaming::Document>(
document,
origin);
if (!PruneDestroyedAndSet(_streamedDocuments, document, result)) {
_streamedDocuments.emplace_or_assign(document, result);
}
return result;
}
void Session::requestPollViewRepaint(not_null<const PollData*> poll) {
if (const auto i = _pollViews.find(poll); i != _pollViews.end()) {
for (const auto view : i->second) {

View File

@ -43,6 +43,7 @@ class Reader;
} // namespace Clip
namespace Streaming {
class Reader;
class Document;
} // namespace Streaming
} // namespace Media
@ -439,6 +440,9 @@ public:
not_null<DocumentData*> document,
FileOrigin origin,
bool forceRemoteLoader = false);
std::shared_ptr<::Media::Streaming::Document> documentStreamer(
not_null<DocumentData*> document,
FileOrigin origin);
HistoryItem *addNewMessage(
const MTPMessage &data,
@ -956,6 +960,9 @@ private:
base::flat_map<
not_null<DocumentData*>,
std::weak_ptr<::Media::Streaming::Reader>> _streamedReaders;
base::flat_map<
not_null<DocumentData*>,
std::weak_ptr<::Media::Streaming::Document>> _streamedDocuments;
base::flat_map<FolderId, std::unique_ptr<Folder>> _folders;
//rpl::variable<FeedId> _defaultFeedId = FeedId(); // #feed

View File

@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/audio/media_audio.h"
#include "media/clip/media_clip_reader.h"
#include "media/player/media_player_instance.h"
#include "media/streaming/media_streaming_player.h"
#include "media/streaming/media_streaming_document.h"
#include "media/view/media_view_playback_progress.h"
#include "boxes/confirm_box.h"
#include "history/history_item_components.h"
@ -46,17 +46,24 @@ int gifMaxStatusWidth(DocumentData *document) {
struct Gif::Streamed {
Streamed(
not_null<Data::Session*> owner,
std::shared_ptr<::Media::Streaming::Reader> reader);
not_null<DocumentData*> document,
Data::FileOrigin origin);
~Streamed();
::Media::Streaming::Player player;
::Media::Streaming::Information info;
std::shared_ptr<::Media::Streaming::Document> shared;
not_null<::Media::Streaming::Instance*> instance;
rpl::lifetime lifetime;
};
Gif::Streamed::Streamed(
not_null<Data::Session*> owner,
std::shared_ptr<::Media::Streaming::Reader> reader)
: player(owner, std::move(reader)) {
not_null<DocumentData*> document,
Data::FileOrigin origin)
: shared(document->owner().documentStreamer(document, origin))
, instance(shared->addInstance()) {
}
Gif::Streamed::~Streamed() {
shared->removeInstance(instance);
}
Gif::Gif(
@ -378,7 +385,7 @@ void Gif::draw(Painter &p, const QRect &r, TextSelection selection, crl::time ms
App::complexOverlayRect(p, rthumb, roundRadius, roundCorners);
}
if (radial || (!player && ((_streamed && _streamed->player.failed()) || (!_data->loaded() && !_data->loading()) || !autoplayEnabled()))) {
if (radial || (!player && ((_streamed && _streamed->shared->player().failed()) || (!_data->loaded() && !_data->loading()) || !autoplayEnabled()))) {
auto radialOpacity = (radial && _data->loaded() && item->id > 0) ? _animation->radial.opacity() : 1.;
auto inner = QRect(rthumb.x() + (rthumb.width() - st::msgFileSize) / 2, rthumb.y() + (rthumb.height() - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
p.setPen(Qt::NoPen);
@ -814,15 +821,15 @@ int Gif::additionalWidth(const HistoryMessageVia *via, const HistoryMessageReply
return ::Media::Player::instance()->roundVideoPlayer(_parent->data());
}
::Media::Streaming::Player *Gif::activeOwnPlayer() const {
const ::Media::Streaming::Player *Gif::activeOwnPlayer() const {
return (_streamed
&& _streamed->player.ready()
&& !_streamed->player.videoSize().isEmpty())
? &_streamed->player
&& _streamed->shared->player().ready()
&& !_streamed->shared->player().videoSize().isEmpty())
? &_streamed->shared->player()
: nullptr;
}
::Media::Streaming::Player *Gif::activeCurrentPlayer() const {
const ::Media::Streaming::Player *Gif::activeCurrentPlayer() const {
if (const auto player = activeRoundPlayer()) {
return player;
}
@ -890,28 +897,24 @@ void Gif::playAnimation(bool autoplay) {
options.mode = ::Media::Streaming::Mode::Video;
options.loop = true;
//}
_streamed->player.play(options);
_streamed->shared->play(options);
}
}
void Gif::createStreamedPlayer() {
setStreamed(std::make_unique<Streamed>(
&_data->owner(),
_data->owner().documentStreamedReader(
_data,
_realParent->fullId())));
setStreamed(std::make_unique<Streamed>(_data, _realParent->fullId()));
_streamed->player.updates(
_streamed->shared->player().updates(
) | rpl::start_with_next_error([=](::Media::Streaming::Update &&update) {
handleStreamingUpdate(std::move(update));
}, [=](::Media::Streaming::Error &&error) {
handleStreamingError(std::move(error));
}, _streamed->player.lifetime());
}, _streamed->lifetime);
_streamed->player.fullInCache(
_streamed->shared->player().fullInCache(
) | rpl::start_with_next([=](bool fullInCache) {
_data->setLoadedInMediaCache(fullInCache);
}, _streamed->player.lifetime());
}, _streamed->lifetime);
}
void Gif::setStreamed(std::unique_ptr<Streamed> value) {
@ -932,10 +935,8 @@ void Gif::handleStreamingUpdate(::Media::Streaming::Update &&update) {
update.data.match([&](Information &update) {
streamingReady(std::move(update));
}, [&](const PreloadedVideo &update) {
_streamed->info.video.state.receivedTill = update.till;
//updatePlaybackState();
}, [&](const UpdateVideo &update) {
_streamed->info.video.state.position = update.position;
history()->owner().requestViewRepaint(_parent);
Core::App().updateNonIdle();
//updatePlaybackState();
@ -949,11 +950,6 @@ void Gif::handleStreamingUpdate(::Media::Streaming::Update &&update) {
//playbackWaitingChange(update.waiting);
}, [&](MutedByOther) {
}, [&](Finished) {
const auto finishTrack = [](TrackState &state) {
state.position = state.receivedTill = state.duration;
};
finishTrack(_streamed->info.audio.state);
finishTrack(_streamed->info.video.state);
//updatePlaybackState();
});
}
@ -974,7 +970,6 @@ void Gif::handleStreamingError(::Media::Streaming::Error &&error) {
}
void Gif::streamingReady(::Media::Streaming::Information &&info) {
_streamed->info = std::move(info);
history()->owner().requestViewResize(_parent);
//validateStreamedGoodThumbnail();
//if (videoShown()) {

View File

@ -94,8 +94,8 @@ private:
QSize countCurrentSize(int newWidth) override;
QSize videoSize() const;
::Media::Streaming::Player *activeRoundPlayer() const;
::Media::Streaming::Player *activeOwnPlayer() const;
::Media::Streaming::Player *activeCurrentPlayer() const;
const ::Media::Streaming::Player *activeOwnPlayer() const;
const ::Media::Streaming::Player *activeCurrentPlayer() const;
::Media::View::PlaybackProgress *videoPlayback() const;
void createStreamedPlayer();

View File

@ -51,12 +51,12 @@ Document::Document(
handleUpdate(std::move(update));
}, [=](Streaming::Error &&error) {
handleError(std::move(error));
}, lifetime());
}, _player.lifetime());
_player.fullInCache(
) | rpl::start_with_next([=](bool fullInCache) {
_document->setLoadedInMediaCache(fullInCache);
}, lifetime());
}, _player.lifetime());
}
const Player &Document::player() const {
@ -124,10 +124,6 @@ Ui::RadialState Document::waitingState() const {
return _radial.computeState();
}
rpl::lifetime &Document::lifetime() {
return _player.lifetime();
}
void Document::handleUpdate(Update &&update) {
update.data.match([&](Information &update) {
ready(std::move(update));

View File

@ -53,8 +53,6 @@ public:
[[nodiscard]] float64 waitingOpacity() const;
[[nodiscard]] Ui::RadialState waitingState() const;
[[nodiscard]] rpl::lifetime &lifetime();
private:
void waitingCallback();

View File

@ -190,8 +190,9 @@ struct OverlayWidget::Streamed {
QWidget *controlsParent,
not_null<PlaybackControls::Delegate*> controlsDelegate,
Callback &&loadingCallback);
~Streamed();
Streaming::Document document;
std::shared_ptr<Streaming::Document> shared;
not_null<Streaming::Instance*> instance;
PlaybackControls controls;
@ -200,6 +201,8 @@ struct OverlayWidget::Streamed {
bool withSound = false;
bool pausedBySeek = false;
bool resumeOnCallEnd = false;
rpl::lifetime lifetime;
};
template <typename Callback>
@ -209,12 +212,16 @@ OverlayWidget::Streamed::Streamed(
QWidget *controlsParent,
not_null<PlaybackControls::Delegate*> controlsDelegate,
Callback &&loadingCallback)
: document(document, origin)
, instance(this->document.addInstance())
: shared(document->owner().documentStreamer(document, origin))
, instance(shared->addInstance())
, controls(controlsParent, controlsDelegate) {
instance->setWaitingCallback(std::forward<Callback>(loadingCallback));
}
OverlayWidget::Streamed::~Streamed() {
shared->removeInstance(instance);
}
OverlayWidget::OverlayWidget()
: OverlayParent(nullptr)
, _transparentBrush(style::transparentPlaceholderBrush())
@ -360,13 +367,13 @@ void OverlayWidget::moveToScreen(bool force) {
}
bool OverlayWidget::videoShown() const {
return _streamed && !_streamed->document.info().video.cover.isNull();
return _streamed && !_streamed->shared->info().video.cover.isNull();
}
QSize OverlayWidget::videoSize() const {
Expects(videoShown());
return _streamed->document.info().video.size;
return _streamed->shared->info().video.size;
}
bool OverlayWidget::videoIsGifv() const {
@ -380,9 +387,9 @@ QImage OverlayWidget::videoFrame() const {
//request.radius = (_doc && _doc->isVideoMessage())
// ? ImageRoundRadius::Ellipse
// : ImageRoundRadius::None;
return _streamed->document.player().ready()
? _streamed->document.player().frame(request)
: _streamed->document.info().video.cover;
return _streamed->shared->player().ready()
? _streamed->shared->player().frame(request)
: _streamed->shared->info().video.cover;
}
QImage OverlayWidget::videoFrameForDirectPaint() const {
@ -2000,12 +2007,12 @@ void OverlayWidget::initStreaming() {
Core::App().updateNonIdle();
_streamed->document.player().updates(
_streamed->shared->player().updates(
) | rpl::start_with_next_error([=](Streaming::Update &&update) {
handleStreamingUpdate(std::move(update));
}, [=](Streaming::Error &&error) {
handleStreamingError(std::move(error));
}, _streamed->document.lifetime());
}, _streamed->lifetime);
restartAtSeekPosition(0);
}
@ -2085,14 +2092,14 @@ void OverlayWidget::createStreamingObjects() {
QImage OverlayWidget::transformVideoFrame(QImage frame) const {
Expects(videoShown());
if (_streamed->document.info().video.rotation != 0) {
if (_streamed->shared->info().video.rotation != 0) {
auto transform = QTransform();
transform.rotate(_streamed->document.info().video.rotation);
transform.rotate(_streamed->shared->info().video.rotation);
frame = frame.transformed(transform);
}
if (frame.size() != _streamed->document.info().video.size) {
if (frame.size() != _streamed->shared->info().video.size) {
frame = frame.scaled(
_streamed->document.info().video.size,
_streamed->shared->info().video.size,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
}
@ -2269,18 +2276,18 @@ void OverlayWidget::playbackPauseResume() {
Expects(_streamed != nullptr);
_streamed->resumeOnCallEnd = false;
if (_streamed->document.player().failed()) {
if (_streamed->shared->player().failed()) {
clearStreaming();
initStreaming();
} else if (_streamed->document.player().finished()) {
} else if (_streamed->shared->player().finished()) {
_streamingStartPaused = false;
restartAtSeekPosition(0);
} else if (_streamed->document.player().paused()) {
_streamed->document.resume();
} else if (_streamed->shared->player().paused()) {
_streamed->shared->resume();
updatePlaybackState();
playbackPauseMusic();
} else {
_streamed->document.pause();
_streamed->shared->pause();
updatePlaybackState();
}
}
@ -2290,7 +2297,7 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
Expects(_doc != nullptr);
if (videoShown()) {
_streamed->document.saveFrameToCover();
_streamed->shared->saveFrameToCover();
_current = Images::PixmapFast(transformVideoFrame(videoFrame()));
update(contentRect());
}
@ -2301,9 +2308,9 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
options.mode = Streaming::Mode::Video;
options.loop = true;
}
_streamed->document.play(options);
_streamed->shared->play(options);
if (_streamingStartPaused) {
_streamed->document.pause();
_streamed->shared->pause();
} else {
playbackPauseMusic();
}
@ -2315,8 +2322,8 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
void OverlayWidget::playbackControlsSeekProgress(crl::time position) {
Expects(_streamed != nullptr);
if (!_streamed->document.player().paused()
&& !_streamed->document.player().finished()) {
if (!_streamed->shared->player().paused()
&& !_streamed->shared->player().finished()) {
_streamed->pausedBySeek = true;
playbackControlsPause();
}
@ -2326,7 +2333,7 @@ void OverlayWidget::playbackControlsSeekFinished(crl::time position) {
Expects(_streamed != nullptr);
_streamingStartPaused = !_streamed->pausedBySeek
&& !_streamed->document.player().finished();
&& !_streamed->shared->player().finished();
restartAtSeekPosition(position);
}
@ -2364,12 +2371,12 @@ void OverlayWidget::playbackToggleFullScreen() {
void OverlayWidget::playbackPauseOnCall() {
Expects(_streamed != nullptr);
if (_streamed->document.player().finished()
|| _streamed->document.player().paused()) {
if (_streamed->shared->player().finished()
|| _streamed->shared->player().paused()) {
return;
}
_streamed->resumeOnCallEnd = true;
_streamed->document.pause();
_streamed->shared->pause();
updatePlaybackState();
}
@ -2378,7 +2385,7 @@ void OverlayWidget::playbackResumeOnCall() {
if (_streamed->resumeOnCallEnd) {
_streamed->resumeOnCallEnd = false;
_streamed->document.resume();
_streamed->shared->resume();
updatePlaybackState();
playbackPauseMusic();
}
@ -2400,7 +2407,7 @@ void OverlayWidget::updatePlaybackState() {
if (videoIsGifv()) {
return;
}
const auto state = _streamed->document.player().prepareLegacyState();
const auto state = _streamed->shared->player().prepareLegacyState();
if (state.position != kTimeUnknown && state.length != kTimeUnknown) {
_streamed->controls.updatePlayback(state);
}
@ -2704,7 +2711,7 @@ void OverlayWidget::paintEvent(QPaintEvent *e) {
void OverlayWidget::checkGroupThumbsAnimation() {
if (_groupThumbs
&& (!_streamed || _streamed->document.player().ready())) {
&& (!_streamed || _streamed->shared->player().ready())) {
_groupThumbs->checkForAnimationStart();
}
}
@ -2716,7 +2723,7 @@ void OverlayWidget::paintTransformedVideoFrame(Painter &p) {
// const auto fill = rect.intersected(this->rect());
// PaintImageProfile(p, image, rect, fill);
//} else {
const auto rotation = _streamed->document.info().video.rotation;
const auto rotation = _streamed->shared->info().video.rotation;
const auto rotated = [](QRect rect, int rotation) {
switch (rotation) {
case 0: return rect;
@ -2756,7 +2763,7 @@ void OverlayWidget::paintRadialLoading(
bool radial,
float64 radialOpacity) {
if (_streamed) {
if (!_streamed->document.waitingShown()) {
if (!_streamed->shared->waitingShown()) {
return;
}
} else if (!radial && (!_doc || _doc->loaded())) {
@ -2809,11 +2816,11 @@ void OverlayWidget::paintRadialLoadingContent(
if (_streamed) {
paintBg(
_streamed->document.waitingOpacity(),
_streamed->shared->waitingOpacity(),
st::radialBg);
Ui::InfiniteRadialAnimation::Draw(
p,
_streamed->document.waitingState(),
_streamed->shared->waitingState(),
arc.topLeft(),
arc.size(),
width(),