rssguard/src/librssguard/gui/reusable/mediaplayer.cpp
2023-11-24 09:50:17 +01:00

308 lines
9.5 KiB
C++

// For license of this file, see <project-root-folder>/LICENSE.md.
#include "mediaplayer.h"
#include "miscellaneous/iconfactory.h"
#if QT_VERSION_MAJOR == 6
#include <QAudioOutput>
#endif
MediaPlayer::MediaPlayer(QWidget* parent)
: TabContent(parent),
#if QT_VERSION_MAJOR == 6
m_audio(new QAudioOutput(this)),
#endif
m_player(new QMediaPlayer(this)), m_muted(false) {
m_ui.setupUi(this);
m_player->setVideoOutput(m_ui.m_video);
#if QT_VERSION_MAJOR == 6
m_player->setAudioOutput(m_audio);
#endif
setupIcons();
createConnections();
onPlaybackStateChanged(QMediaPlayer::PLAYBACK_STATE::StoppedState);
onMediaStatusChanged(QMediaPlayer::MediaStatus::NoMedia);
}
MediaPlayer::~MediaPlayer() {}
WebBrowser* MediaPlayer::webBrowser() const {
return nullptr;
}
void MediaPlayer::playUrl(const QString& url) {
if (m_muted) {
muteUnmute();
}
else {
setVolume(m_ui.m_slidVolume->value());
}
#if QT_VERSION_MAJOR == 6
m_player->setSource(url);
#else
m_player->setMedia(QUrl(url));
#endif
m_player->play();
}
void MediaPlayer::playPause() {
if (m_player->PLAYBACK_STATE_METHOD() != QMediaPlayer::PLAYBACK_STATE::PlayingState) {
m_player->play();
}
else {
m_player->pause();
}
}
void MediaPlayer::stop() {
m_player->stop();
}
void MediaPlayer::download() {
emit urlDownloadRequested(
#if QT_VERSION_MAJOR == 6
m_player->source()
#else
m_player->media().request().url()
#endif
);
}
void MediaPlayer::muteUnmute() {
m_ui.m_slidVolume->setEnabled(m_muted);
setVolume(m_muted ? m_ui.m_slidVolume->value() : 0);
m_muted = !m_muted;
}
void MediaPlayer::setSpeed(int speed) {
m_player->setPlaybackRate(convertSpeed(speed));
}
void MediaPlayer::setVolume(int volume) {
#if QT_VERSION_MAJOR == 6
m_player->audioOutput()->setVolume(convertSliderVolume(volume));
#else
m_player->setVolume(volume);
#endif
m_ui.m_btnVolume->setIcon(volume <= 0 ? m_iconMute : m_iconUnmute);
}
void MediaPlayer::seek(int position) {
m_player->setPosition(convertSliderProgress(position));
}
void MediaPlayer::onPlaybackRateChanged(qreal speed) {
m_ui.m_spinSpeed->blockSignals(true);
m_ui.m_spinSpeed->setValue(convertSpinSpeed(speed));
m_ui.m_spinSpeed->blockSignals(false);
}
void MediaPlayer::onDurationChanged(qint64 duration) {
m_ui.m_slidProgress->blockSignals(true);
m_ui.m_slidProgress->setMaximum(convertDuration(duration));
m_ui.m_slidProgress->blockSignals(false);
updateTimeAndProgress(convertToSliderProgress(m_player->position()), convertDuration(duration));
}
void MediaPlayer::onPositionChanged(qint64 position) {
m_ui.m_slidProgress->blockSignals(true);
m_ui.m_slidProgress->setValue(convertToSliderProgress(position));
m_ui.m_slidProgress->blockSignals(false);
updateTimeAndProgress(convertToSliderProgress(position), convertDuration(m_player->duration()));
}
void MediaPlayer::updateTimeAndProgress(int progress, int total) {
m_ui.m_lblTime->setText(QSL("%1/%2").arg(QDateTime::fromSecsSinceEpoch(progress).toUTC().toString("hh:mm:ss"),
QDateTime::fromSecsSinceEpoch(total).toUTC().toString("hh:mm:ss")));
}
void MediaPlayer::onErrorOccurred(QMediaPlayer::Error error, const QString& error_string) {
QString err = error_string.isEmpty() ? errorToString(error) : error_string;
m_ui.m_lblStatus->setStatus(WidgetWithStatus::StatusType::Error, err, err);
}
void MediaPlayer::onAudioAvailable(bool available) {
m_ui.m_slidVolume->setEnabled(available);
m_ui.m_btnVolume->setEnabled(available);
}
void MediaPlayer::onVideoAvailable(bool available) {
Q_UNUSED(available)
}
void MediaPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status) {
QString st = mediaStatusToString(status);
m_ui.m_lblStatus->setStatus(status == QMediaPlayer::MediaStatus::InvalidMedia
? WidgetWithStatus::StatusType::Error
: WidgetWithStatus::StatusType::Information,
st,
st);
}
void MediaPlayer::onPlaybackStateChanged(QMediaPlayer::PLAYBACK_STATE state) {
switch (state) {
case QMediaPlayer::PLAYBACK_STATE::StoppedState:
m_ui.m_btnPlayPause->setIcon(m_iconPlay);
m_ui.m_btnStop->setEnabled(false);
break;
case QMediaPlayer::PLAYBACK_STATE::PlayingState:
m_ui.m_btnPlayPause->setIcon(m_iconPause);
m_ui.m_btnStop->setEnabled(true);
break;
case QMediaPlayer::PLAYBACK_STATE::PausedState:
m_ui.m_btnPlayPause->setIcon(m_iconPlay);
m_ui.m_btnStop->setEnabled(true);
break;
}
}
int MediaPlayer::convertToSliderProgress(qint64 player_progress) const {
return player_progress / 1000;
}
int MediaPlayer::convertDuration(qint64 duration) const {
return duration / 1000;
}
qreal MediaPlayer::convertSpeed(int speed) const {
return speed / 100.0;
}
int MediaPlayer::convertSpinSpeed(qreal speed) const {
return speed * 100;
}
void MediaPlayer::onSeekableChanged(bool seekable) {
m_ui.m_slidProgress->setEnabled(seekable);
if (!seekable) {
onPositionChanged(0);
}
}
QString MediaPlayer::errorToString(QMediaPlayer::Error error) const {
switch (error) {
case QMediaPlayer::ResourceError:
return tr("Cannot load media (missing codecs)");
case QMediaPlayer::FormatError:
return tr("Unrecognized format");
case QMediaPlayer::NetworkError:
return tr("Network problem");
case QMediaPlayer::AccessDeniedError:
return tr("Access denied");
#if QT_VERSION_MAJOR == 5
case QMediaPlayer::ServiceMissingError:
return tr("Service is missing");
case QMediaPlayer::MediaIsPlaylist:
return tr("This is playlist");
#endif
case QMediaPlayer::NoError:
return tr("No errors");
default:
return tr("Unknown error");
}
}
float MediaPlayer::convertSliderVolume(int slider_volume) const {
return slider_volume / 100.0f;
}
qint64 MediaPlayer::convertSliderProgress(int slider_progress) const {
return qint64(slider_progress) * qint64(1000);
}
QString MediaPlayer::mediaStatusToString(QMediaPlayer::MediaStatus status) const {
switch (status) {
case QMediaPlayer::NoMedia:
return tr("No media");
case QMediaPlayer::LoadingMedia:
return tr("Loading...");
case QMediaPlayer::LoadedMedia:
return tr("Media loaded");
case QMediaPlayer::StalledMedia:
return tr("Media stalled");
case QMediaPlayer::BufferingMedia:
return tr("Buffering...");
case QMediaPlayer::BufferedMedia:
return tr("Loaded");
case QMediaPlayer::EndOfMedia:
return tr("Ended");
case QMediaPlayer::InvalidMedia:
return tr("Media is invalid");
default:
return tr("Unknown");
}
}
void MediaPlayer::setupIcons() {
m_iconPlay = qApp->icons()->fromTheme(QSL("media-playback-start"), QSL("player_play"));
m_iconPause = qApp->icons()->fromTheme(QSL("media-playback-pause"), QSL("player_pause"));
m_iconMute = qApp->icons()->fromTheme(QSL("player-volume-muted"), QSL("audio-volume-muted"));
m_iconUnmute = qApp->icons()->fromTheme(QSL("player-volume"), QSL("stock_volume"));
m_ui.m_btnDownload->setIcon(qApp->icons()->fromTheme(QSL("download"), QSL("browser-download")));
m_ui.m_btnStop->setIcon(qApp->icons()->fromTheme(QSL("media-playback-stop"), QSL("player_stop")));
}
void MediaPlayer::createConnections() {
connect(m_player, &QMediaPlayer::durationChanged, this, &MediaPlayer::onDurationChanged);
#if QT_VERSION_MAJOR == 6
connect(m_player, &QMediaPlayer::errorOccurred, this, &MediaPlayer::onErrorOccurred);
#else
connect(m_player, QOverload<QMediaPlayer::Error>::of(&QMediaPlayer::error), this, [this](QMediaPlayer::Error error) {
onErrorOccurred(error);
});
#endif
#if QT_VERSION_MAJOR == 6
connect(m_player, &QMediaPlayer::hasAudioChanged, this, &MediaPlayer::onAudioAvailable);
connect(m_player, &QMediaPlayer::hasVideoChanged, this, &MediaPlayer::onVideoAvailable);
connect(m_player, &QMediaPlayer::playbackStateChanged, this, &MediaPlayer::onPlaybackStateChanged);
#else
connect(m_player, &QMediaPlayer::audioAvailableChanged, this, &MediaPlayer::onAudioAvailable);
connect(m_player, &QMediaPlayer::videoAvailableChanged, this, &MediaPlayer::onVideoAvailable);
connect(m_player, &QMediaPlayer::stateChanged, this, &MediaPlayer::onPlaybackStateChanged);
#endif
connect(m_player, &QMediaPlayer::mediaStatusChanged, this, &MediaPlayer::onMediaStatusChanged);
connect(m_player, &QMediaPlayer::positionChanged, this, &MediaPlayer::onPositionChanged);
connect(m_player, &QMediaPlayer::seekableChanged, this, &MediaPlayer::onSeekableChanged);
connect(m_player, &QMediaPlayer::playbackRateChanged, this, &MediaPlayer::onPlaybackRateChanged);
connect(m_ui.m_btnPlayPause, &PlainToolButton::clicked, this, &MediaPlayer::playPause);
connect(m_ui.m_btnStop, &PlainToolButton::clicked, this, &MediaPlayer::stop);
connect(m_ui.m_btnDownload, &PlainToolButton::clicked, this, &MediaPlayer::download);
connect(m_ui.m_btnVolume, &PlainToolButton::clicked, this, &MediaPlayer::muteUnmute);
connect(m_ui.m_slidVolume, &QSlider::valueChanged, this, &MediaPlayer::setVolume);
connect(m_ui.m_slidProgress, &QSlider::valueChanged, this, &MediaPlayer::seek);
connect(m_ui.m_spinSpeed, &QSpinBox::valueChanged, this, &MediaPlayer::setSpeed);
}