mirror of https://github.com/procxx/kepka.git
Make some video player code reusable.
This commit is contained in:
parent
c7836be614
commit
b73f1be856
|
@ -617,6 +617,8 @@ PRIVATE
|
|||
media/streaming/media_streaming_audio_track.cpp
|
||||
media/streaming/media_streaming_audio_track.h
|
||||
media/streaming/media_streaming_common.h
|
||||
media/streaming/media_streaming_document.cpp
|
||||
media/streaming/media_streaming_document.h
|
||||
media/streaming/media_streaming_file.cpp
|
||||
media/streaming/media_streaming_file.h
|
||||
media/streaming/media_streaming_file_delegate.h
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
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
|
||||
*/
|
||||
#include "media/streaming/media_streaming_document.h"
|
||||
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "storage/file_download.h" // Storage::kMaxFileInMemory.
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtCore/QBuffer>
|
||||
|
||||
namespace Media {
|
||||
namespace Streaming {
|
||||
namespace {
|
||||
|
||||
constexpr auto kWaitingFastDuration = crl::time(200);
|
||||
constexpr auto kWaitingShowDuration = crl::time(500);
|
||||
constexpr auto kWaitingShowDelay = crl::time(500);
|
||||
constexpr auto kGoodThumbnailQuality = 87;
|
||||
|
||||
} // namespace
|
||||
|
||||
void Instance::setWaitingCallback(Fn<void()> callback) {
|
||||
_waitingCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void Instance::callWaitingCallback() {
|
||||
if (_waitingCallback) {
|
||||
_waitingCallback();
|
||||
}
|
||||
}
|
||||
|
||||
Document::Document(
|
||||
not_null<DocumentData*> document,
|
||||
Data::FileOrigin origin)
|
||||
: _player(
|
||||
&document->owner(),
|
||||
document->owner().documentStreamedReader(document, origin))
|
||||
, _radial(
|
||||
[=] { waitingCallback(); },
|
||||
st::defaultInfiniteRadialAnimation)
|
||||
, _document(document) {
|
||||
_player.updates(
|
||||
) | rpl::start_with_next_error([=](Update &&update) {
|
||||
handleUpdate(std::move(update));
|
||||
}, [=](Streaming::Error &&error) {
|
||||
handleError(std::move(error));
|
||||
}, lifetime());
|
||||
|
||||
_player.fullInCache(
|
||||
) | rpl::start_with_next([=](bool fullInCache) {
|
||||
_document->setLoadedInMediaCache(fullInCache);
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
const Player &Document::player() const {
|
||||
return _player;
|
||||
}
|
||||
|
||||
const Information &Document::info() const {
|
||||
return _info;
|
||||
}
|
||||
|
||||
void Document::play(const PlaybackOptions &options) {
|
||||
_player.play(options);
|
||||
_info.audio.state.position
|
||||
= _info.video.state.position
|
||||
= options.position;
|
||||
waitingChange(true);
|
||||
}
|
||||
|
||||
void Document::pause() {
|
||||
_player.pause();
|
||||
}
|
||||
|
||||
void Document::resume() {
|
||||
_player.resume();
|
||||
}
|
||||
|
||||
void Document::saveFrameToCover() {
|
||||
auto request = Streaming::FrameRequest();
|
||||
//request.radius = (_doc && _doc->isVideoMessage())
|
||||
// ? ImageRoundRadius::Ellipse
|
||||
// : ImageRoundRadius::None;
|
||||
_info.video.cover = _player.ready()
|
||||
? _player.frame(request)
|
||||
: _info.video.cover;
|
||||
}
|
||||
|
||||
not_null<Instance*> Document::addInstance() {
|
||||
return _instances.emplace(std::make_unique<Instance>()).first->get();
|
||||
}
|
||||
|
||||
void Document::removeInstance(not_null<Instance*> instance) {
|
||||
const auto i = ranges::lower_bound(
|
||||
_instances,
|
||||
instance.get(),
|
||||
ranges::less(),
|
||||
&std::unique_ptr<Instance>::get);
|
||||
if (i != _instances.end() && i->get() == instance) {
|
||||
_instances.erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool Document::waitingShown() const {
|
||||
if (!_fading.animating() && !_waiting) {
|
||||
_radial.stop(anim::type::instant);
|
||||
return false;
|
||||
}
|
||||
return _radial.animating();
|
||||
}
|
||||
|
||||
float64 Document::waitingOpacity() const {
|
||||
return _fading.value(_waiting ? 1. : 0.);
|
||||
}
|
||||
|
||||
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));
|
||||
}, [&](const PreloadedVideo &update) {
|
||||
_info.video.state.receivedTill = update.till;
|
||||
}, [&](const UpdateVideo &update) {
|
||||
_info.video.state.position = update.position;
|
||||
}, [&](const PreloadedAudio &update) {
|
||||
_info.audio.state.receivedTill = update.till;
|
||||
}, [&](const UpdateAudio &update) {
|
||||
_info.audio.state.position = update.position;
|
||||
}, [&](const WaitingForData &update) {
|
||||
waitingChange(update.waiting);
|
||||
}, [&](MutedByOther) {
|
||||
}, [&](Finished) {
|
||||
const auto finishTrack = [](TrackState &state) {
|
||||
state.position = state.receivedTill = state.duration;
|
||||
};
|
||||
finishTrack(_info.audio.state);
|
||||
finishTrack(_info.video.state);
|
||||
});
|
||||
}
|
||||
|
||||
void Document::handleError(Error &&error) {
|
||||
if (error == Error::NotStreamable) {
|
||||
_document->setNotSupportsStreaming();
|
||||
} else if (error == Error::OpenFailed) {
|
||||
_document->setInappPlaybackFailed();
|
||||
}
|
||||
waitingChange(false);
|
||||
}
|
||||
|
||||
void Document::ready(Information &&info) {
|
||||
_info = std::move(info);
|
||||
validateGoodThumbnail();
|
||||
waitingChange(false);
|
||||
}
|
||||
|
||||
void Document::waitingChange(bool waiting) {
|
||||
if (_waiting == waiting) {
|
||||
return;
|
||||
}
|
||||
_waiting = waiting;
|
||||
const auto fade = [=](crl::time duration) {
|
||||
if (!_radial.animating()) {
|
||||
_radial.start(
|
||||
st::defaultInfiniteRadialAnimation.sineDuration);
|
||||
}
|
||||
_fading.start(
|
||||
[=] { waitingCallback(); },
|
||||
_waiting ? 0. : 1.,
|
||||
_waiting ? 1. : 0.,
|
||||
duration);
|
||||
};
|
||||
if (waiting) {
|
||||
if (_radial.animating()) {
|
||||
_timer.cancel();
|
||||
fade(kWaitingFastDuration);
|
||||
} else {
|
||||
_timer.callOnce(kWaitingShowDelay);
|
||||
_timer.setCallback([=] {
|
||||
fade(kWaitingShowDuration);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_timer.cancel();
|
||||
if (_radial.animating()) {
|
||||
fade(kWaitingFastDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Document::validateGoodThumbnail() {
|
||||
const auto good = _document->goodThumbnail();
|
||||
if (_info.video.cover.isNull()
|
||||
|| (good && good->loaded())
|
||||
|| _document->uploading()) {
|
||||
return;
|
||||
}
|
||||
auto image = [&] {
|
||||
auto result = _info.video.cover;
|
||||
if (_info.video.rotation != 0) {
|
||||
auto transform = QTransform();
|
||||
transform.rotate(_info.video.rotation);
|
||||
result = result.transformed(transform);
|
||||
}
|
||||
if (result.size() != _info.video.size) {
|
||||
result = result.scaled(
|
||||
_info.video.size,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
|
||||
auto bytes = QByteArray();
|
||||
{
|
||||
auto buffer = QBuffer(&bytes);
|
||||
image.save(&buffer, "JPG", kGoodThumbnailQuality);
|
||||
}
|
||||
const auto length = bytes.size();
|
||||
if (!length || length > Storage::kMaxFileInMemory) {
|
||||
LOG(("App Error: Bad thumbnail data for saving to cache."));
|
||||
} else if (_document->uploading()) {
|
||||
_document->setGoodThumbnailOnUpload(
|
||||
std::move(image),
|
||||
std::move(bytes));
|
||||
} else {
|
||||
_document->owner().cache().putIfEmpty(
|
||||
_document->goodThumbnailCacheKey(),
|
||||
Storage::Cache::Database::TaggedValue(
|
||||
std::move(bytes),
|
||||
Data::kImageCacheTag));
|
||||
_document->refreshGoodThumbnail();
|
||||
}
|
||||
}
|
||||
|
||||
void Document::waitingCallback() {
|
||||
for (const auto &instance : _instances) {
|
||||
instance->callWaitingCallback();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Streaming
|
||||
} // namespace Media
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
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_player.h"
|
||||
#include "ui/effects/radial_animation.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
class DocumentData;
|
||||
|
||||
namespace Data {
|
||||
struct FileOrigin;
|
||||
} // namespace Data
|
||||
|
||||
namespace Media {
|
||||
namespace Streaming {
|
||||
|
||||
class Instance {
|
||||
public:
|
||||
void setWaitingCallback(Fn<void()> callback);
|
||||
|
||||
void callWaitingCallback();
|
||||
|
||||
private:
|
||||
Fn<void()> _waitingCallback;
|
||||
|
||||
};
|
||||
|
||||
class Document {
|
||||
public:
|
||||
Document(
|
||||
not_null<DocumentData*> document,
|
||||
Data::FileOrigin origin);
|
||||
|
||||
[[nodiscard]] const Player &player() const;
|
||||
[[nodiscard]] const Information &info() const;
|
||||
|
||||
void play(const PlaybackOptions &options);
|
||||
void pause();
|
||||
void resume();
|
||||
void saveFrameToCover();
|
||||
|
||||
[[nodiscard]] not_null<Instance*> addInstance();
|
||||
void removeInstance(not_null<Instance*> instance);
|
||||
|
||||
[[nodiscard]] bool waitingShown() const;
|
||||
[[nodiscard]] float64 waitingOpacity() const;
|
||||
[[nodiscard]] Ui::RadialState waitingState() const;
|
||||
|
||||
[[nodiscard]] rpl::lifetime &lifetime();
|
||||
|
||||
private:
|
||||
void waitingCallback();
|
||||
|
||||
void handleUpdate(Update &&update);
|
||||
void handleError(Error &&error);
|
||||
|
||||
void ready(Information &&info);
|
||||
void waitingChange(bool waiting);
|
||||
|
||||
void validateGoodThumbnail();
|
||||
|
||||
Player _player;
|
||||
Information _info;
|
||||
|
||||
bool _waiting = false;
|
||||
mutable Ui::InfiniteRadialAnimation _radial;
|
||||
Ui::Animations::Simple _fading;
|
||||
base::Timer _timer;
|
||||
base::flat_set<std::unique_ptr<Instance>> _instances;
|
||||
|
||||
not_null<DocumentData*> _document;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace Streaming
|
||||
} // namespace Media
|
|
@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "media/view/media_view_group_thumbs.h"
|
||||
#include "media/streaming/media_streaming_player.h"
|
||||
#include "media/streaming/media_streaming_reader.h"
|
||||
#include "media/streaming/media_streaming_document.h"
|
||||
#include "media/player/media_player_instance.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_message.h"
|
||||
|
@ -66,10 +67,6 @@ namespace Media {
|
|||
namespace View {
|
||||
namespace {
|
||||
|
||||
constexpr auto kGoodThumbnailQuality = 87;
|
||||
constexpr auto kWaitingFastDuration = crl::time(200);
|
||||
constexpr auto kWaitingShowDuration = crl::time(500);
|
||||
constexpr auto kWaitingShowDelay = crl::time(500);
|
||||
constexpr auto kPreloadCount = 4;
|
||||
|
||||
// macOS OpenGL renderer fails to render larger texture
|
||||
|
@ -188,20 +185,16 @@ struct OverlayWidget::Collage {
|
|||
struct OverlayWidget::Streamed {
|
||||
template <typename Callback>
|
||||
Streamed(
|
||||
not_null<Data::Session*> owner,
|
||||
std::shared_ptr<Streaming::Reader> reader,
|
||||
not_null<DocumentData*> document,
|
||||
Data::FileOrigin origin,
|
||||
QWidget *controlsParent,
|
||||
not_null<PlaybackControls::Delegate*> controlsDelegate,
|
||||
Callback &&loadingCallback);
|
||||
|
||||
Streaming::Player player;
|
||||
Streaming::Information info;
|
||||
Streaming::Document document;
|
||||
not_null<Streaming::Instance*> instance;
|
||||
PlaybackControls controls;
|
||||
|
||||
bool waiting = false;
|
||||
Ui::InfiniteRadialAnimation radial;
|
||||
Ui::Animations::Simple fading;
|
||||
base::Timer timer;
|
||||
QImage frameForDirectPaint;
|
||||
|
||||
bool withSound = false;
|
||||
|
@ -211,16 +204,15 @@ struct OverlayWidget::Streamed {
|
|||
|
||||
template <typename Callback>
|
||||
OverlayWidget::Streamed::Streamed(
|
||||
not_null<Data::Session*> owner,
|
||||
std::shared_ptr<Streaming::Reader> reader,
|
||||
not_null<DocumentData*> document,
|
||||
Data::FileOrigin origin,
|
||||
QWidget *controlsParent,
|
||||
not_null<PlaybackControls::Delegate*> controlsDelegate,
|
||||
Callback &&loadingCallback)
|
||||
: player(owner, std::move(reader))
|
||||
, controls(controlsParent, controlsDelegate)
|
||||
, radial(
|
||||
std::forward<Callback>(loadingCallback),
|
||||
st::mediaviewStreamingRadial) {
|
||||
: document(document, origin)
|
||||
, instance(this->document.addInstance())
|
||||
, controls(controlsParent, controlsDelegate) {
|
||||
instance->setWaitingCallback(std::forward<Callback>(loadingCallback));
|
||||
}
|
||||
|
||||
OverlayWidget::OverlayWidget()
|
||||
|
@ -368,13 +360,13 @@ void OverlayWidget::moveToScreen(bool force) {
|
|||
}
|
||||
|
||||
bool OverlayWidget::videoShown() const {
|
||||
return _streamed && !_streamed->info.video.cover.isNull();
|
||||
return _streamed && !_streamed->document.info().video.cover.isNull();
|
||||
}
|
||||
|
||||
QSize OverlayWidget::videoSize() const {
|
||||
Expects(videoShown());
|
||||
|
||||
return _streamed->info.video.size;
|
||||
return _streamed->document.info().video.size;
|
||||
}
|
||||
|
||||
bool OverlayWidget::videoIsGifv() const {
|
||||
|
@ -388,9 +380,9 @@ QImage OverlayWidget::videoFrame() const {
|
|||
//request.radius = (_doc && _doc->isVideoMessage())
|
||||
// ? ImageRoundRadius::Ellipse
|
||||
// : ImageRoundRadius::None;
|
||||
return _streamed->player.ready()
|
||||
? _streamed->player.frame(request)
|
||||
: _streamed->info.video.cover;
|
||||
return _streamed->document.player().ready()
|
||||
? _streamed->document.player().frame(request)
|
||||
: _streamed->document.info().video.cover;
|
||||
}
|
||||
|
||||
QImage OverlayWidget::videoFrameForDirectPaint() const {
|
||||
|
@ -2008,17 +2000,12 @@ void OverlayWidget::initStreaming() {
|
|||
|
||||
Core::App().updateNonIdle();
|
||||
|
||||
_streamed->player.updates(
|
||||
_streamed->document.player().updates(
|
||||
) | rpl::start_with_next_error([=](Streaming::Update &&update) {
|
||||
handleStreamingUpdate(std::move(update));
|
||||
}, [=](Streaming::Error &&error) {
|
||||
handleStreamingError(std::move(error));
|
||||
}, _streamed->player.lifetime());
|
||||
|
||||
_streamed->player.fullInCache(
|
||||
) | rpl::start_with_next([=](bool fullInCache) {
|
||||
_doc->setLoadedInMediaCache(fullInCache);
|
||||
}, _streamed->player.lifetime());
|
||||
}, _streamed->document.lifetime());
|
||||
|
||||
restartAtSeekPosition(0);
|
||||
}
|
||||
|
@ -2063,8 +2050,6 @@ void OverlayWidget::initStreamingThumbnail() {
|
|||
}
|
||||
|
||||
void OverlayWidget::streamingReady(Streaming::Information &&info) {
|
||||
_streamed->info = std::move(info);
|
||||
validateStreamedGoodThumbnail();
|
||||
if (videoShown()) {
|
||||
const auto contentSize = style::ConvertScale(videoSize());
|
||||
if (contentSize != QSize(_width, _height)) {
|
||||
|
@ -2075,13 +2060,12 @@ void OverlayWidget::streamingReady(Streaming::Information &&info) {
|
|||
}
|
||||
}
|
||||
this->update(contentRect());
|
||||
playbackWaitingChange(false);
|
||||
}
|
||||
|
||||
void OverlayWidget::createStreamingObjects() {
|
||||
_streamed = std::make_unique<Streamed>(
|
||||
&_doc->owner(),
|
||||
_doc->owner().documentStreamedReader(_doc, fileOrigin()),
|
||||
_doc,
|
||||
fileOrigin(),
|
||||
this,
|
||||
static_cast<PlaybackControls::Delegate*>(this),
|
||||
[=] { waitingAnimationCallback(); });
|
||||
|
@ -2101,79 +2085,38 @@ void OverlayWidget::createStreamingObjects() {
|
|||
QImage OverlayWidget::transformVideoFrame(QImage frame) const {
|
||||
Expects(videoShown());
|
||||
|
||||
if (_streamed->info.video.rotation != 0) {
|
||||
if (_streamed->document.info().video.rotation != 0) {
|
||||
auto transform = QTransform();
|
||||
transform.rotate(_streamed->info.video.rotation);
|
||||
transform.rotate(_streamed->document.info().video.rotation);
|
||||
frame = frame.transformed(transform);
|
||||
}
|
||||
if (frame.size() != _streamed->info.video.size) {
|
||||
if (frame.size() != _streamed->document.info().video.size) {
|
||||
frame = frame.scaled(
|
||||
_streamed->info.video.size,
|
||||
_streamed->document.info().video.size,
|
||||
Qt::IgnoreAspectRatio,
|
||||
Qt::SmoothTransformation);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
void OverlayWidget::validateStreamedGoodThumbnail() {
|
||||
Expects(_streamed != nullptr);
|
||||
Expects(_doc != nullptr);
|
||||
|
||||
const auto good = _doc->goodThumbnail();
|
||||
if (!videoShown() || (good && good->loaded()) || _doc->uploading()) {
|
||||
return;
|
||||
}
|
||||
auto image = transformVideoFrame(_streamed->info.video.cover);
|
||||
auto bytes = QByteArray();
|
||||
{
|
||||
auto buffer = QBuffer(&bytes);
|
||||
image.save(&buffer, "JPG", kGoodThumbnailQuality);
|
||||
}
|
||||
const auto length = bytes.size();
|
||||
if (!length || length > Storage::kMaxFileInMemory) {
|
||||
LOG(("App Error: Bad thumbnail data for saving to cache."));
|
||||
} else if (_doc->uploading()) {
|
||||
_doc->setGoodThumbnailOnUpload(
|
||||
std::move(image),
|
||||
std::move(bytes));
|
||||
} else {
|
||||
_doc->owner().cache().putIfEmpty(
|
||||
_doc->goodThumbnailCacheKey(),
|
||||
Storage::Cache::Database::TaggedValue(
|
||||
std::move(bytes),
|
||||
Data::kImageCacheTag));
|
||||
_doc->refreshGoodThumbnail();
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayWidget::handleStreamingUpdate(Streaming::Update &&update) {
|
||||
using namespace Streaming;
|
||||
|
||||
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;
|
||||
this->update(contentRect());
|
||||
Core::App().updateNonIdle();
|
||||
updatePlaybackState();
|
||||
}, [&](const PreloadedAudio &update) {
|
||||
_streamed->info.audio.state.receivedTill = update.till;
|
||||
updatePlaybackState();
|
||||
}, [&](const UpdateAudio &update) {
|
||||
_streamed->info.audio.state.position = update.position;
|
||||
updatePlaybackState();
|
||||
}, [&](const WaitingForData &update) {
|
||||
playbackWaitingChange(update.waiting);
|
||||
}, [&](WaitingForData) {
|
||||
}, [&](MutedByOther) {
|
||||
}, [&](Finished) {
|
||||
const auto finishTrack = [](Streaming::TrackState &state) {
|
||||
state.position = state.receivedTill = state.duration;
|
||||
};
|
||||
finishTrack(_streamed->info.audio.state);
|
||||
finishTrack(_streamed->info.video.state);
|
||||
updatePlaybackState();
|
||||
});
|
||||
}
|
||||
|
@ -2187,47 +2130,10 @@ void OverlayWidget::handleStreamingError(Streaming::Error &&error) {
|
|||
if (!_doc->canBePlayed()) {
|
||||
redisplayContent();
|
||||
} else {
|
||||
playbackWaitingChange(false);
|
||||
updatePlaybackState();
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayWidget::playbackWaitingChange(bool waiting) {
|
||||
Expects(_streamed != nullptr);
|
||||
|
||||
if (_streamed->waiting == waiting) {
|
||||
return;
|
||||
}
|
||||
_streamed->waiting = waiting;
|
||||
const auto fade = [=](crl::time duration) {
|
||||
if (!_streamed->radial.animating()) {
|
||||
_streamed->radial.start(
|
||||
st::defaultInfiniteRadialAnimation.sineDuration);
|
||||
}
|
||||
_streamed->fading.start(
|
||||
[=] { update(radialRect()); },
|
||||
_streamed->waiting ? 0. : 1.,
|
||||
_streamed->waiting ? 1. : 0.,
|
||||
duration);
|
||||
};
|
||||
if (waiting) {
|
||||
if (_streamed->radial.animating()) {
|
||||
_streamed->timer.cancel();
|
||||
fade(kWaitingFastDuration);
|
||||
} else {
|
||||
_streamed->timer.callOnce(kWaitingShowDelay);
|
||||
_streamed->timer.setCallback([=] {
|
||||
fade(kWaitingShowDuration);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
_streamed->timer.cancel();
|
||||
if (_streamed->radial.animating()) {
|
||||
fade(kWaitingFastDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverlayWidget::initThemePreview() {
|
||||
using namespace Window::Theme;
|
||||
|
||||
|
@ -2363,18 +2269,18 @@ void OverlayWidget::playbackPauseResume() {
|
|||
Expects(_streamed != nullptr);
|
||||
|
||||
_streamed->resumeOnCallEnd = false;
|
||||
if (_streamed->player.failed()) {
|
||||
if (_streamed->document.player().failed()) {
|
||||
clearStreaming();
|
||||
initStreaming();
|
||||
} else if (_streamed->player.finished()) {
|
||||
} else if (_streamed->document.player().finished()) {
|
||||
_streamingStartPaused = false;
|
||||
restartAtSeekPosition(0);
|
||||
} else if (_streamed->player.paused()) {
|
||||
_streamed->player.resume();
|
||||
} else if (_streamed->document.player().paused()) {
|
||||
_streamed->document.resume();
|
||||
updatePlaybackState();
|
||||
playbackPauseMusic();
|
||||
} else {
|
||||
_streamed->player.pause();
|
||||
_streamed->document.pause();
|
||||
updatePlaybackState();
|
||||
}
|
||||
}
|
||||
|
@ -2384,7 +2290,7 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
|
|||
Expects(_doc != nullptr);
|
||||
|
||||
if (videoShown()) {
|
||||
_streamed->info.video.cover = videoFrame();
|
||||
_streamed->document.saveFrameToCover();
|
||||
_current = Images::PixmapFast(transformVideoFrame(videoFrame()));
|
||||
update(contentRect());
|
||||
}
|
||||
|
@ -2395,25 +2301,22 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
|
|||
options.mode = Streaming::Mode::Video;
|
||||
options.loop = true;
|
||||
}
|
||||
_streamed->player.play(options);
|
||||
_streamed->document.play(options);
|
||||
if (_streamingStartPaused) {
|
||||
_streamed->player.pause();
|
||||
_streamed->document.pause();
|
||||
} else {
|
||||
playbackPauseMusic();
|
||||
}
|
||||
_streamed->pausedBySeek = false;
|
||||
|
||||
_streamed->info.audio.state.position
|
||||
= _streamed->info.video.state.position
|
||||
= position;
|
||||
updatePlaybackState();
|
||||
playbackWaitingChange(true);
|
||||
}
|
||||
|
||||
void OverlayWidget::playbackControlsSeekProgress(crl::time position) {
|
||||
Expects(_streamed != nullptr);
|
||||
|
||||
if (!_streamed->player.paused() && !_streamed->player.finished()) {
|
||||
if (!_streamed->document.player().paused()
|
||||
&& !_streamed->document.player().finished()) {
|
||||
_streamed->pausedBySeek = true;
|
||||
playbackControlsPause();
|
||||
}
|
||||
|
@ -2423,7 +2326,7 @@ void OverlayWidget::playbackControlsSeekFinished(crl::time position) {
|
|||
Expects(_streamed != nullptr);
|
||||
|
||||
_streamingStartPaused = !_streamed->pausedBySeek
|
||||
&& !_streamed->player.finished();
|
||||
&& !_streamed->document.player().finished();
|
||||
restartAtSeekPosition(position);
|
||||
}
|
||||
|
||||
|
@ -2461,11 +2364,12 @@ void OverlayWidget::playbackToggleFullScreen() {
|
|||
void OverlayWidget::playbackPauseOnCall() {
|
||||
Expects(_streamed != nullptr);
|
||||
|
||||
if (_streamed->player.finished() || _streamed->player.paused()) {
|
||||
if (_streamed->document.player().finished()
|
||||
|| _streamed->document.player().paused()) {
|
||||
return;
|
||||
}
|
||||
_streamed->resumeOnCallEnd = true;
|
||||
_streamed->player.pause();
|
||||
_streamed->document.pause();
|
||||
updatePlaybackState();
|
||||
}
|
||||
|
||||
|
@ -2474,7 +2378,7 @@ void OverlayWidget::playbackResumeOnCall() {
|
|||
|
||||
if (_streamed->resumeOnCallEnd) {
|
||||
_streamed->resumeOnCallEnd = false;
|
||||
_streamed->player.resume();
|
||||
_streamed->document.resume();
|
||||
updatePlaybackState();
|
||||
playbackPauseMusic();
|
||||
}
|
||||
|
@ -2496,7 +2400,7 @@ void OverlayWidget::updatePlaybackState() {
|
|||
if (videoIsGifv()) {
|
||||
return;
|
||||
}
|
||||
const auto state = _streamed->player.prepareLegacyState();
|
||||
const auto state = _streamed->document.player().prepareLegacyState();
|
||||
if (state.position != kTimeUnknown && state.length != kTimeUnknown) {
|
||||
_streamed->controls.updatePlayback(state);
|
||||
}
|
||||
|
@ -2799,7 +2703,8 @@ void OverlayWidget::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
void OverlayWidget::checkGroupThumbsAnimation() {
|
||||
if (_groupThumbs && (!_streamed || _streamed->player.ready())) {
|
||||
if (_groupThumbs
|
||||
&& (!_streamed || _streamed->document.player().ready())) {
|
||||
_groupThumbs->checkForAnimationStart();
|
||||
}
|
||||
}
|
||||
|
@ -2811,7 +2716,7 @@ void OverlayWidget::paintTransformedVideoFrame(Painter &p) {
|
|||
// const auto fill = rect.intersected(this->rect());
|
||||
// PaintImageProfile(p, image, rect, fill);
|
||||
//} else {
|
||||
const auto rotation = _streamed->info.video.rotation;
|
||||
const auto rotation = _streamed->document.info().video.rotation;
|
||||
const auto rotated = [](QRect rect, int rotation) {
|
||||
switch (rotation) {
|
||||
case 0: return rect;
|
||||
|
@ -2851,13 +2756,7 @@ void OverlayWidget::paintRadialLoading(
|
|||
bool radial,
|
||||
float64 radialOpacity) {
|
||||
if (_streamed) {
|
||||
if (!_streamed->radial.animating()) {
|
||||
return;
|
||||
}
|
||||
if (!_streamed->fading.animating() && !_streamed->waiting) {
|
||||
if (!_streamed->waiting) {
|
||||
_streamed->radial.stop(anim::type::instant);
|
||||
}
|
||||
if (!_streamed->document.waitingShown()) {
|
||||
return;
|
||||
}
|
||||
} else if (!radial && (!_doc || _doc->loaded())) {
|
||||
|
@ -2910,9 +2809,16 @@ void OverlayWidget::paintRadialLoadingContent(
|
|||
|
||||
if (_streamed) {
|
||||
paintBg(
|
||||
_streamed->fading.value(_streamed->waiting ? 1. : 0.),
|
||||
_streamed->document.waitingOpacity(),
|
||||
st::radialBg);
|
||||
_streamed->radial.draw(p, arc.topLeft(), arc.size(), width());
|
||||
Ui::InfiniteRadialAnimation::Draw(
|
||||
p,
|
||||
_streamed->document.waitingState(),
|
||||
arc.topLeft(),
|
||||
arc.size(),
|
||||
width(),
|
||||
st::radialFg,
|
||||
st::radialLine);
|
||||
return;
|
||||
}
|
||||
if (_photo) {
|
||||
|
|
|
@ -178,7 +178,6 @@ private:
|
|||
void playbackPauseOnCall();
|
||||
void playbackResumeOnCall();
|
||||
void playbackPauseMusic();
|
||||
void playbackWaitingChange(bool waiting);
|
||||
|
||||
void updateOver(QPoint mpos);
|
||||
void moveToScreen(bool force = false);
|
||||
|
@ -265,7 +264,6 @@ private:
|
|||
void createStreamingObjects();
|
||||
void handleStreamingUpdate(Streaming::Update &&update);
|
||||
void handleStreamingError(Streaming::Error &&error);
|
||||
void validateStreamedGoodThumbnail();
|
||||
|
||||
void initThemePreview();
|
||||
void destroyThemePreview();
|
||||
|
|
|
@ -188,11 +188,6 @@ mediaviewGroupWidthMax: 160px;
|
|||
mediaviewGroupSkip: 3px;
|
||||
mediaviewGroupSkipCurrent: 12px;
|
||||
|
||||
mediaviewStreamingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
|
||||
color: radialFg;
|
||||
thickness: radialLine;
|
||||
}
|
||||
|
||||
themePreviewSize: size(903px, 584px);
|
||||
themePreviewBg: windowBg;
|
||||
themePreviewOverlayOpacity: 0.8;
|
||||
|
|
|
@ -512,6 +512,8 @@
|
|||
<(src_loc)/media/streaming/media_streaming_audio_track.cpp
|
||||
<(src_loc)/media/streaming/media_streaming_audio_track.h
|
||||
<(src_loc)/media/streaming/media_streaming_common.h
|
||||
<(src_loc)/media/streaming/media_streaming_document.cpp
|
||||
<(src_loc)/media/streaming/media_streaming_document.h
|
||||
<(src_loc)/media/streaming/media_streaming_file.cpp
|
||||
<(src_loc)/media/streaming/media_streaming_file.h
|
||||
<(src_loc)/media/streaming/media_streaming_file_delegate.h
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 604f62599e9ee5f4d57d778ebbe9403c2a875245
|
||||
Subproject commit 21b976569ae2051955c7346295c7029a75bf1bbc
|
Loading…
Reference in New Issue