mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-04-01 23:00:58 +00:00
Add video speed control slider.
This commit is contained in:
parent
b88219902f
commit
87cc18aff8
@ -23,6 +23,14 @@ constexpr auto kVersionTag = -1;
|
|||||||
constexpr auto kVersion = 1;
|
constexpr auto kVersion = 1;
|
||||||
constexpr auto kMaxSavedPlaybackPositions = 16;
|
constexpr auto kMaxSavedPlaybackPositions = 16;
|
||||||
|
|
||||||
|
[[nodiscard]] qint32 SerializePlaybackSpeed(float64 speed) {
|
||||||
|
return int(std::round(std::clamp(speed * 4., 2., 8.))) - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 DeserializePlaybackSpeed(qint32 speed) {
|
||||||
|
return (std::clamp(speed, 0, 6) + 2) / 4.;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Settings::Variables::Variables()
|
Settings::Variables::Variables()
|
||||||
@ -98,6 +106,7 @@ QByteArray Settings::serialize() const {
|
|||||||
for (const auto &[id, time] : _variables.mediaLastPlaybackPosition) {
|
for (const auto &[id, time] : _variables.mediaLastPlaybackPosition) {
|
||||||
stream << quint64(id) << qint64(time);
|
stream << quint64(id) << qint64(time);
|
||||||
}
|
}
|
||||||
|
stream << qint32(SerializePlaybackSpeed(_variables.videoPlaybackSpeed.current()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -148,6 +157,7 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
|
|||||||
qint32 suggestStickersByEmoji = _variables.suggestStickersByEmoji ? 1 : 0;
|
qint32 suggestStickersByEmoji = _variables.suggestStickersByEmoji ? 1 : 0;
|
||||||
qint32 spellcheckerEnabled = _variables.spellcheckerEnabled.current() ? 1 : 0;
|
qint32 spellcheckerEnabled = _variables.spellcheckerEnabled.current() ? 1 : 0;
|
||||||
std::vector<std::pair<DocumentId, crl::time>> mediaLastPlaybackPosition;
|
std::vector<std::pair<DocumentId, crl::time>> mediaLastPlaybackPosition;
|
||||||
|
qint32 videoPlaybackSpeed = SerializePlaybackSpeed(_variables.videoPlaybackSpeed.current());
|
||||||
|
|
||||||
stream >> versionTag;
|
stream >> versionTag;
|
||||||
if (versionTag == kVersionTag) {
|
if (versionTag == kVersionTag) {
|
||||||
@ -268,6 +278,9 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!stream.atEnd()) {
|
||||||
|
stream >> videoPlaybackSpeed;
|
||||||
|
}
|
||||||
if (stream.status() != QDataStream::Ok) {
|
if (stream.status() != QDataStream::Ok) {
|
||||||
LOG(("App Error: "
|
LOG(("App Error: "
|
||||||
"Bad data for Main::Settings::constructFromSerialized()"));
|
"Bad data for Main::Settings::constructFromSerialized()"));
|
||||||
@ -355,6 +368,7 @@ void Settings::constructFromSerialized(const QByteArray &serialized) {
|
|||||||
_variables.suggestStickersByEmoji = (suggestStickersByEmoji == 1);
|
_variables.suggestStickersByEmoji = (suggestStickersByEmoji == 1);
|
||||||
_variables.spellcheckerEnabled = (spellcheckerEnabled == 1);
|
_variables.spellcheckerEnabled = (spellcheckerEnabled == 1);
|
||||||
_variables.mediaLastPlaybackPosition = std::move(mediaLastPlaybackPosition);
|
_variables.mediaLastPlaybackPosition = std::move(mediaLastPlaybackPosition);
|
||||||
|
_variables.videoPlaybackSpeed = DeserializePlaybackSpeed(videoPlaybackSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::setSupportChatsTimeSlice(int slice) {
|
void Settings::setSupportChatsTimeSlice(int slice) {
|
||||||
|
@ -241,6 +241,13 @@ public:
|
|||||||
return _variables.spellcheckerEnabled.changes();
|
return _variables.spellcheckerEnabled.changes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] float64 videoPlaybackSpeed() const {
|
||||||
|
return _variables.videoPlaybackSpeed.current();
|
||||||
|
}
|
||||||
|
void setVideoPlaybackSpeed(float64 speed) {
|
||||||
|
_variables.videoPlaybackSpeed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Variables {
|
struct Variables {
|
||||||
Variables();
|
Variables();
|
||||||
@ -281,6 +288,7 @@ private:
|
|||||||
bool suggestStickersByEmoji = true;
|
bool suggestStickersByEmoji = true;
|
||||||
rpl::variable<bool> spellcheckerEnabled = true;
|
rpl::variable<bool> spellcheckerEnabled = true;
|
||||||
std::vector<std::pair<DocumentId, crl::time>> mediaLastPlaybackPosition;
|
std::vector<std::pair<DocumentId, crl::time>> mediaLastPlaybackPosition;
|
||||||
|
rpl::variable<float64> videoPlaybackSpeed = 1.;
|
||||||
|
|
||||||
static constexpr auto kDefaultSupportChatsLimitSlice
|
static constexpr auto kDefaultSupportChatsLimitSlice
|
||||||
= 7 * 24 * 60 * 60;
|
= 7 * 24 * 60 * 60;
|
||||||
|
@ -958,6 +958,7 @@ void Player::unlock() {
|
|||||||
--_locks;
|
--_locks;
|
||||||
if (!_locks) {
|
if (!_locks) {
|
||||||
stopAudio();
|
stopAudio();
|
||||||
|
setSpeed(1.);
|
||||||
setWaitForMarkAsShown(true);
|
setWaitForMarkAsShown(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2361,8 +2361,11 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
|
|||||||
if (!_streamed->withSound) {
|
if (!_streamed->withSound) {
|
||||||
options.mode = Streaming::Mode::Video;
|
options.mode = Streaming::Mode::Video;
|
||||||
options.loop = true;
|
options.loop = true;
|
||||||
} else if (_pip) {
|
} else {
|
||||||
_pip = nullptr;
|
options.speed = _doc->session().settings().videoPlaybackSpeed();
|
||||||
|
if (_pip) {
|
||||||
|
_pip = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_streamed->instance.play(options);
|
_streamed->instance.play(options);
|
||||||
if (_streamingStartPaused) {
|
if (_streamingStartPaused) {
|
||||||
@ -2397,13 +2400,29 @@ void OverlayWidget::playbackControlsVolumeChanged(float64 volume) {
|
|||||||
Global::SetVideoVolume(volume);
|
Global::SetVideoVolume(volume);
|
||||||
updateMixerVideoVolume();
|
updateMixerVideoVolume();
|
||||||
Global::RefVideoVolumeChanged().notify();
|
Global::RefVideoVolumeChanged().notify();
|
||||||
Auth().saveSettingsDelayed();
|
if (_doc) {
|
||||||
|
_doc->session().saveSettingsDelayed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float64 OverlayWidget::playbackControlsCurrentVolume() {
|
float64 OverlayWidget::playbackControlsCurrentVolume() {
|
||||||
return Global::VideoVolume();
|
return Global::VideoVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OverlayWidget::playbackControlsSpeedChanged(float64 speed) {
|
||||||
|
if (_doc) {
|
||||||
|
_doc->session().settings().setVideoPlaybackSpeed(speed);
|
||||||
|
_doc->session().saveSettingsDelayed();
|
||||||
|
}
|
||||||
|
if (_streamed && !videoIsGifv()) {
|
||||||
|
_streamed->instance.setSpeed(speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 OverlayWidget::playbackControlsCurrentSpeed() {
|
||||||
|
return _doc ? _doc->session().settings().videoPlaybackSpeed() : 1.;
|
||||||
|
}
|
||||||
|
|
||||||
void OverlayWidget::switchToPip() {
|
void OverlayWidget::switchToPip() {
|
||||||
const auto document = _doc;
|
const auto document = _doc;
|
||||||
const auto msgId = _msgid;
|
const auto msgId = _msgid;
|
||||||
|
@ -172,6 +172,8 @@ private:
|
|||||||
void playbackControlsSeekFinished(crl::time position) override;
|
void playbackControlsSeekFinished(crl::time position) override;
|
||||||
void playbackControlsVolumeChanged(float64 volume) override;
|
void playbackControlsVolumeChanged(float64 volume) override;
|
||||||
float64 playbackControlsCurrentVolume() override;
|
float64 playbackControlsCurrentVolume() override;
|
||||||
|
void playbackControlsSpeedChanged(float64 speed);
|
||||||
|
float64 playbackControlsCurrentSpeed() override;
|
||||||
void playbackControlsToFullScreen() override;
|
void playbackControlsToFullScreen() override;
|
||||||
void playbackControlsFromFullScreen() override;
|
void playbackControlsFromFullScreen() override;
|
||||||
void playbackControlsToPictureInPicture() override;
|
void playbackControlsToPictureInPicture() override;
|
||||||
|
@ -11,6 +11,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "media/streaming/media_streaming_document.h"
|
#include "media/streaming/media_streaming_document.h"
|
||||||
#include "media/streaming/media_streaming_utility.h"
|
#include "media/streaming/media_streaming_utility.h"
|
||||||
#include "media/audio/media_audio.h"
|
#include "media/audio/media_audio.h"
|
||||||
|
#include "main/main_session.h"
|
||||||
|
#include "main/main_settings.h"
|
||||||
|
#include "data/data_document.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "ui/platform/ui_platform_utility.h"
|
#include "ui/platform/ui_platform_utility.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
@ -721,6 +724,9 @@ void Pip::restartAtSeekPosition(crl::time position) {
|
|||||||
auto options = Streaming::PlaybackOptions();
|
auto options = Streaming::PlaybackOptions();
|
||||||
options.position = position;
|
options.position = position;
|
||||||
options.audioId = _instance.player().prepareLegacyState().id;
|
options.audioId = _instance.player().prepareLegacyState().id;
|
||||||
|
options.speed = options.audioId.audio()
|
||||||
|
? options.audioId.audio()->session().settings().videoPlaybackSpeed()
|
||||||
|
: 1.;
|
||||||
_instance.play(options);
|
_instance.play(options);
|
||||||
updatePlaybackState();
|
updatePlaybackState();
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ PlaybackControls::PlaybackControls(
|
|||||||
, _playbackSlider(this, st::mediaviewPlayback)
|
, _playbackSlider(this, st::mediaviewPlayback)
|
||||||
, _playbackProgress(std::make_unique<PlaybackProgress>())
|
, _playbackProgress(std::make_unique<PlaybackProgress>())
|
||||||
, _volumeController(this, st::mediaviewPlayback)
|
, _volumeController(this, st::mediaviewPlayback)
|
||||||
|
, _speedController(this, st::mediaviewPlayback)
|
||||||
, _fullScreenToggle(this, st::mediaviewFullScreenButton)
|
, _fullScreenToggle(this, st::mediaviewFullScreenButton)
|
||||||
, _pictureInPicture(this, st::mediaviewFullScreenButton)
|
, _pictureInPicture(this, st::mediaviewFullScreenButton)
|
||||||
, _playedAlready(this, st::mediaviewPlayProgressLabel)
|
, _playedAlready(this, st::mediaviewPlayProgressLabel)
|
||||||
@ -54,6 +55,12 @@ PlaybackControls::PlaybackControls(
|
|||||||
_volumeController->setChangeProgressCallback([=](float64 value) {
|
_volumeController->setChangeProgressCallback([=](float64 value) {
|
||||||
_delegate->playbackControlsVolumeChanged(value);
|
_delegate->playbackControlsVolumeChanged(value);
|
||||||
});
|
});
|
||||||
|
_speedController->setPseudoDiscrete(
|
||||||
|
7,
|
||||||
|
[=](int index) { return (index + 2) / 4.; },
|
||||||
|
_delegate->playbackControlsCurrentSpeed(),
|
||||||
|
[=](float64 speed) { _delegate->playbackControlsSpeedChanged(speed); });
|
||||||
|
_speedController->setAlwaysDisplayMarker(false);
|
||||||
|
|
||||||
_playPauseResume->addClickHandler([=] {
|
_playPauseResume->addClickHandler([=] {
|
||||||
if (_showPause) {
|
if (_showPause) {
|
||||||
@ -121,6 +128,7 @@ void PlaybackControls::startFading(Callback start) {
|
|||||||
showChildren();
|
showChildren();
|
||||||
_playbackSlider->disablePaint(true);
|
_playbackSlider->disablePaint(true);
|
||||||
_volumeController->disablePaint(true);
|
_volumeController->disablePaint(true);
|
||||||
|
_speedController->disablePaint(true);
|
||||||
_childrenHidden = false;
|
_childrenHidden = false;
|
||||||
}
|
}
|
||||||
start();
|
start();
|
||||||
@ -128,7 +136,8 @@ void PlaybackControls::startFading(Callback start) {
|
|||||||
for (const auto child : children()) {
|
for (const auto child : children()) {
|
||||||
if (child->isWidgetType()
|
if (child->isWidgetType()
|
||||||
&& child != _playbackSlider
|
&& child != _playbackSlider
|
||||||
&& child != _volumeController) {
|
&& child != _volumeController
|
||||||
|
&& child != _speedController) {
|
||||||
static_cast<QWidget*>(child)->hide();
|
static_cast<QWidget*>(child)->hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,6 +147,7 @@ void PlaybackControls::startFading(Callback start) {
|
|||||||
}
|
}
|
||||||
_playbackSlider->disablePaint(false);
|
_playbackSlider->disablePaint(false);
|
||||||
_volumeController->disablePaint(false);
|
_volumeController->disablePaint(false);
|
||||||
|
_speedController->disablePaint(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackControls::showAnimated() {
|
void PlaybackControls::showAnimated() {
|
||||||
@ -159,6 +169,7 @@ void PlaybackControls::fadeFinished() {
|
|||||||
void PlaybackControls::fadeUpdated(float64 opacity) {
|
void PlaybackControls::fadeUpdated(float64 opacity) {
|
||||||
_playbackSlider->setFadeOpacity(opacity);
|
_playbackSlider->setFadeOpacity(opacity);
|
||||||
_volumeController->setFadeOpacity(opacity);
|
_volumeController->setFadeOpacity(opacity);
|
||||||
|
_speedController->setFadeOpacity(opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackControls::updatePlayback(const Player::TrackState &state) {
|
void PlaybackControls::updatePlayback(const Player::TrackState &state) {
|
||||||
@ -306,8 +317,12 @@ void PlaybackControls::resizeEvent(QResizeEvent *e) {
|
|||||||
|
|
||||||
_pictureInPicture->moveToLeft(left, playTop);
|
_pictureInPicture->moveToLeft(left, playTop);
|
||||||
|
|
||||||
|
const auto volumeTop = playTop + (_fullScreenToggle->height() - _volumeController->height()) / 2;
|
||||||
_volumeController->resize(st::mediaviewVolumeWidth, st::mediaviewPlayback.seekSize.height());
|
_volumeController->resize(st::mediaviewVolumeWidth, st::mediaviewPlayback.seekSize.height());
|
||||||
_volumeController->moveToRight(skip, playTop + (_fullScreenToggle->height() - _volumeController->height()) / 2);
|
_volumeController->moveToRight(skip, volumeTop);
|
||||||
|
|
||||||
|
_speedController->resize(st::mediaviewVolumeWidth, st::mediaviewPlayback.seekSize.height());
|
||||||
|
_speedController->moveToRight(skip + _volumeController->width() + skip, volumeTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaybackControls::paintEvent(QPaintEvent *e) {
|
void PlaybackControls::paintEvent(QPaintEvent *e) {
|
||||||
@ -320,6 +335,7 @@ void PlaybackControls::paintEvent(QPaintEvent *e) {
|
|||||||
showChildren();
|
showChildren();
|
||||||
_playbackSlider->setFadeOpacity(1.);
|
_playbackSlider->setFadeOpacity(1.);
|
||||||
_volumeController->setFadeOpacity(1.);
|
_volumeController->setFadeOpacity(1.);
|
||||||
|
_speedController->setFadeOpacity(1.);
|
||||||
_childrenHidden = false;
|
_childrenHidden = false;
|
||||||
}
|
}
|
||||||
App::roundRect(p, rect(), st::mediaviewSaveMsgBg, MediaviewSaveCorners);
|
App::roundRect(p, rect(), st::mediaviewSaveMsgBg, MediaviewSaveCorners);
|
||||||
|
@ -36,6 +36,8 @@ public:
|
|||||||
virtual void playbackControlsSeekFinished(crl::time position) = 0;
|
virtual void playbackControlsSeekFinished(crl::time position) = 0;
|
||||||
virtual void playbackControlsVolumeChanged(float64 volume) = 0;
|
virtual void playbackControlsVolumeChanged(float64 volume) = 0;
|
||||||
[[nodiscard]] virtual float64 playbackControlsCurrentVolume() = 0;
|
[[nodiscard]] virtual float64 playbackControlsCurrentVolume() = 0;
|
||||||
|
virtual void playbackControlsSpeedChanged(float64 speed) = 0;
|
||||||
|
[[nodiscard]] virtual float64 playbackControlsCurrentSpeed() = 0;
|
||||||
virtual void playbackControlsToFullScreen() = 0;
|
virtual void playbackControlsToFullScreen() = 0;
|
||||||
virtual void playbackControlsFromFullScreen() = 0;
|
virtual void playbackControlsFromFullScreen() = 0;
|
||||||
virtual void playbackControlsToPictureInPicture() = 0;
|
virtual void playbackControlsToPictureInPicture() = 0;
|
||||||
@ -90,6 +92,7 @@ private:
|
|||||||
std::unique_ptr<PlaybackProgress> _playbackProgress;
|
std::unique_ptr<PlaybackProgress> _playbackProgress;
|
||||||
std::unique_ptr<PlaybackProgress> _receivedTillProgress;
|
std::unique_ptr<PlaybackProgress> _receivedTillProgress;
|
||||||
object_ptr<Ui::MediaSlider> _volumeController;
|
object_ptr<Ui::MediaSlider> _volumeController;
|
||||||
|
object_ptr<Ui::MediaSlider> _speedController;
|
||||||
object_ptr<Ui::IconButton> _fullScreenToggle;
|
object_ptr<Ui::IconButton> _fullScreenToggle;
|
||||||
object_ptr<Ui::IconButton> _pictureInPicture;
|
object_ptr<Ui::IconButton> _pictureInPicture;
|
||||||
object_ptr<Ui::LabelSimple> _playedAlready;
|
object_ptr<Ui::LabelSimple> _playedAlready;
|
||||||
|
Loading…
Reference in New Issue
Block a user