fix: refine playback shutdown and danmaku sizing
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# Maintainer: local
|
# Maintainer: local
|
||||||
|
|
||||||
pkgname=qemby
|
pkgname=qemby
|
||||||
pkgver=0.0.6
|
pkgver=0.0.7
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="Desktop client for Emby and Jellyfin media servers"
|
pkgdesc="Desktop client for Emby and Jellyfin media servers"
|
||||||
arch=('x86_64')
|
arch=('x86_64')
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ bool MpvController::init() {
|
|||||||
|
|
||||||
mpv_set_option_string(m_mpv, "sub-hinting", "none");
|
mpv_set_option_string(m_mpv, "sub-hinting", "none");
|
||||||
mpv_set_option_string(m_mpv, "sub-ass-hinting", "none");
|
mpv_set_option_string(m_mpv, "sub-ass-hinting", "none");
|
||||||
mpv_request_log_messages(m_mpv, "info");
|
mpv_request_log_messages(m_mpv, "warn");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -223,6 +223,10 @@ bool MpvController::init() {
|
|||||||
observeProperty("track-list", MPV_FORMAT_NODE);
|
observeProperty("track-list", MPV_FORMAT_NODE);
|
||||||
observeProperty("sid", MPV_FORMAT_NODE);
|
observeProperty("sid", MPV_FORMAT_NODE);
|
||||||
observeProperty("secondary-sid", MPV_FORMAT_NODE);
|
observeProperty("secondary-sid", MPV_FORMAT_NODE);
|
||||||
|
observeProperty("video-params/dw", MPV_FORMAT_DOUBLE);
|
||||||
|
observeProperty("video-params/dh", MPV_FORMAT_DOUBLE);
|
||||||
|
observeProperty("width", MPV_FORMAT_INT64);
|
||||||
|
observeProperty("height", MPV_FORMAT_INT64);
|
||||||
|
|
||||||
|
|
||||||
observeProperty("paused-for-cache", MPV_FORMAT_FLAG);
|
observeProperty("paused-for-cache", MPV_FORMAT_FLAG);
|
||||||
@@ -289,7 +293,10 @@ void MpvController::eventHandler() {
|
|||||||
auto *msg = static_cast<mpv_event_log_message *>(event->data);
|
auto *msg = static_cast<mpv_event_log_message *>(event->data);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
|
|
||||||
qDebug().noquote() << QString("[MPV %1] %2").arg(msg->prefix, QString::fromUtf8(msg->text).trimmed());
|
qWarning().noquote()
|
||||||
|
<< QString("[MPV %1] %2")
|
||||||
|
.arg(msg->prefix,
|
||||||
|
QString::fromUtf8(msg->text).trimmed());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ void NativeDanmakuOverlay::setRenderOptions(DanmakuRenderOptions options)
|
|||||||
|
|
||||||
const bool appearanceChanged = !renderAppearanceEqual(m_options, options);
|
const bool appearanceChanged = !renderAppearanceEqual(m_options, options);
|
||||||
m_options = options;
|
m_options = options;
|
||||||
|
markSurfaceRectDirty();
|
||||||
requestScheduleRebuild(false, appearanceChanged);
|
requestScheduleRebuild(false, appearanceChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -274,6 +275,7 @@ void NativeDanmakuOverlay::setBottomSubtitleProtected(bool enabled)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_bottomSubtitleProtected = enabled;
|
m_bottomSubtitleProtected = enabled;
|
||||||
|
markSurfaceRectDirty();
|
||||||
requestScheduleRebuild(false, false);
|
requestScheduleRebuild(false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,7 +293,7 @@ void NativeDanmakuOverlay::paintEvent(QPaintEvent *event)
|
|||||||
painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||||
|
|
||||||
const qreal positionMs = currentPositionMsPrecise();
|
const qreal positionMs = currentPositionMsPrecise();
|
||||||
const QRectF surfaceRect = effectiveSurfaceRect();
|
const QRectF surfaceRect = cachedEffectiveSurfaceRect();
|
||||||
const qreal dpr = std::max<qreal>(1.0, devicePixelRatioF());
|
const qreal dpr = std::max<qreal>(1.0, devicePixelRatioF());
|
||||||
const auto alignToDevicePixel = [dpr](qreal value) {
|
const auto alignToDevicePixel = [dpr](qreal value) {
|
||||||
return std::round(value * dpr) / dpr;
|
return std::round(value * dpr) / dpr;
|
||||||
@@ -336,6 +338,7 @@ void NativeDanmakuOverlay::paintEvent(QPaintEvent *event)
|
|||||||
void NativeDanmakuOverlay::resizeEvent(QResizeEvent *event)
|
void NativeDanmakuOverlay::resizeEvent(QResizeEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::resizeEvent(event);
|
QWidget::resizeEvent(event);
|
||||||
|
markSurfaceRectDirty();
|
||||||
requestScheduleRebuild(false, false);
|
requestScheduleRebuild(false, false);
|
||||||
updateScreenRefreshBinding();
|
updateScreenRefreshBinding();
|
||||||
}
|
}
|
||||||
@@ -390,7 +393,7 @@ void NativeDanmakuOverlay::rebuildScheduleNow()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QRectF surfaceRect = effectiveSurfaceRect();
|
const QRectF surfaceRect = cachedEffectiveSurfaceRect();
|
||||||
const qreal viewportScale = viewportScaleForSize(size());
|
const qreal viewportScale = viewportScaleForSize(size());
|
||||||
const QStringList blockedKeywords =
|
const QStringList blockedKeywords =
|
||||||
normalizeBlockedKeywords(m_options.blockedKeywords);
|
normalizeBlockedKeywords(m_options.blockedKeywords);
|
||||||
@@ -738,6 +741,48 @@ void NativeDanmakuOverlay::updateScreenRefreshBinding()
|
|||||||
syncFrameTimer();
|
syncFrameTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeDanmakuOverlay::markSurfaceRectDirty()
|
||||||
|
{
|
||||||
|
m_surfaceRectDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF NativeDanmakuOverlay::cachedEffectiveSurfaceRect() const
|
||||||
|
{
|
||||||
|
if (m_surfaceRectDirty) {
|
||||||
|
m_cachedSurfaceRect = effectiveSurfaceRect();
|
||||||
|
m_surfaceRectDirty = false;
|
||||||
|
}
|
||||||
|
return m_cachedSurfaceRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NativeDanmakuOverlay::updateVideoDisplaySize(const QString &property,
|
||||||
|
const QVariant &value)
|
||||||
|
{
|
||||||
|
qreal *target = nullptr;
|
||||||
|
if (property == QLatin1String("video-params/dw")) {
|
||||||
|
target = &m_videoParamsDisplayWidth;
|
||||||
|
} else if (property == QLatin1String("video-params/dh")) {
|
||||||
|
target = &m_videoParamsDisplayHeight;
|
||||||
|
} else if (property == QLatin1String("width")) {
|
||||||
|
target = &m_videoFallbackWidth;
|
||||||
|
} else if (property == QLatin1String("height")) {
|
||||||
|
target = &m_videoFallbackHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const qreal newValue = value.toDouble();
|
||||||
|
if (std::abs(*target - newValue) <= 0.5) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*target = newValue;
|
||||||
|
markSurfaceRectDirty();
|
||||||
|
requestScheduleRebuild(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
void NativeDanmakuOverlay::refreshBasePosition(qint64 positionMs)
|
void NativeDanmakuOverlay::refreshBasePosition(qint64 positionMs)
|
||||||
{
|
{
|
||||||
m_basePositionMs = std::max<qint64>(0, positionMs);
|
m_basePositionMs = std::max<qint64>(0, positionMs);
|
||||||
@@ -769,20 +814,14 @@ QRectF NativeDanmakuOverlay::effectiveSurfaceRect() const
|
|||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_controller) {
|
const qreal displayWidth =
|
||||||
qreal displayWidth =
|
m_videoParamsDisplayWidth > 0.0 ? m_videoParamsDisplayWidth
|
||||||
m_controller->getProperty(QStringLiteral("video-params/dw")).toDouble();
|
: m_videoFallbackWidth;
|
||||||
qreal displayHeight =
|
const qreal displayHeight =
|
||||||
m_controller->getProperty(QStringLiteral("video-params/dh")).toDouble();
|
m_videoParamsDisplayHeight > 0.0 ? m_videoParamsDisplayHeight
|
||||||
if (displayWidth <= 0.0 || displayHeight <= 0.0) {
|
: m_videoFallbackHeight;
|
||||||
displayWidth =
|
if (displayWidth > 0.0 && displayHeight > 0.0) {
|
||||||
m_controller->getProperty(QStringLiteral("width")).toDouble();
|
if (surface.width() > 0.0 && surface.height() > 0.0) {
|
||||||
displayHeight =
|
|
||||||
m_controller->getProperty(QStringLiteral("height")).toDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (displayWidth > 0.0 && displayHeight > 0.0 &&
|
|
||||||
surface.width() > 0.0 && surface.height() > 0.0) {
|
|
||||||
const qreal videoAspect = displayWidth / displayHeight;
|
const qreal videoAspect = displayWidth / displayHeight;
|
||||||
const qreal viewportAspect = surface.width() / surface.height();
|
const qreal viewportAspect = surface.width() / surface.height();
|
||||||
if (videoAspect > 0.0 && viewportAspect > 0.0) {
|
if (videoAspect > 0.0 && viewportAspect > 0.0) {
|
||||||
@@ -810,7 +849,7 @@ QRectF NativeDanmakuOverlay::effectiveSurfaceRect() const
|
|||||||
|
|
||||||
qreal NativeDanmakuOverlay::laneTop(const ScheduledItem &item) const
|
qreal NativeDanmakuOverlay::laneTop(const ScheduledItem &item) const
|
||||||
{
|
{
|
||||||
const QRectF surfaceRect = effectiveSurfaceRect();
|
const QRectF surfaceRect = cachedEffectiveSurfaceRect();
|
||||||
if (item.type == ItemType::Bottom) {
|
if (item.type == ItemType::Bottom) {
|
||||||
return surfaceRect.bottom() - m_bottomMargin -
|
return surfaceRect.bottom() - m_bottomMargin -
|
||||||
(item.laneIndex + 1) * m_lineHeight;
|
(item.laneIndex + 1) * m_lineHeight;
|
||||||
@@ -901,10 +940,7 @@ void NativeDanmakuOverlay::handleControllerPropertyChanged(const QString &proper
|
|||||||
const qint64 positionMs = currentPositionMs();
|
const qint64 positionMs = currentPositionMs();
|
||||||
m_playbackSpeed = qBound(0.1, value.toDouble(), 16.0);
|
m_playbackSpeed = qBound(0.1, value.toDouble(), 16.0);
|
||||||
refreshBasePosition(positionMs);
|
refreshBasePosition(positionMs);
|
||||||
} else if (property == QLatin1String("video-params/dw") ||
|
} else {
|
||||||
property == QLatin1String("video-params/dh") ||
|
updateVideoDisplaySize(property, value);
|
||||||
property == QLatin1String("width") ||
|
|
||||||
property == QLatin1String("height")) {
|
|
||||||
requestScheduleRebuild(false, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,10 @@ private:
|
|||||||
int targetFrameIntervalMs() const;
|
int targetFrameIntervalMs() const;
|
||||||
QScreen *targetScreen() const;
|
QScreen *targetScreen() const;
|
||||||
void updateScreenRefreshBinding();
|
void updateScreenRefreshBinding();
|
||||||
|
void markSurfaceRectDirty();
|
||||||
|
QRectF cachedEffectiveSurfaceRect() const;
|
||||||
|
void updateVideoDisplaySize(const QString &property,
|
||||||
|
const QVariant &value);
|
||||||
void refreshBasePosition(qint64 positionMs);
|
void refreshBasePosition(qint64 positionMs);
|
||||||
qreal currentPositionMsPrecise() const;
|
qreal currentPositionMsPrecise() const;
|
||||||
qint64 currentPositionMs() const;
|
qint64 currentPositionMs() const;
|
||||||
@@ -111,11 +115,17 @@ private:
|
|||||||
qreal m_outlineSize = 0.0;
|
qreal m_outlineSize = 0.0;
|
||||||
qreal m_shadowOffset = 0.0;
|
qreal m_shadowOffset = 0.0;
|
||||||
qreal m_spritePadding = 0.0;
|
qreal m_spritePadding = 0.0;
|
||||||
|
mutable QRectF m_cachedSurfaceRect;
|
||||||
|
qreal m_videoParamsDisplayWidth = 0.0;
|
||||||
|
qreal m_videoParamsDisplayHeight = 0.0;
|
||||||
|
qreal m_videoFallbackWidth = 0.0;
|
||||||
|
qreal m_videoFallbackHeight = 0.0;
|
||||||
bool m_visibleRequested = false;
|
bool m_visibleRequested = false;
|
||||||
bool m_playbackPaused = true;
|
bool m_playbackPaused = true;
|
||||||
bool m_bottomSubtitleProtected = false;
|
bool m_bottomSubtitleProtected = false;
|
||||||
bool m_scheduleDirty = false;
|
bool m_scheduleDirty = false;
|
||||||
bool m_clearSpriteCacheOnNextRebuild = false;
|
bool m_clearSpriteCacheOnNextRebuild = false;
|
||||||
|
mutable bool m_surfaceRectDirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+46
-26
@@ -101,23 +101,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(m_trayManager, &TrayManager::quitRequested, this, [this]() {
|
connect(m_trayManager, &TrayManager::quitRequested, this,
|
||||||
m_realQuit = true;
|
&MainWindow::requestApplicationQuit);
|
||||||
|
|
||||||
if (auto *player = m_homeView->activePlayerView()) {
|
|
||||||
player->stopAndReport();
|
|
||||||
|
|
||||||
QElapsedTimer wait;
|
|
||||||
wait.start();
|
|
||||||
while (wait.elapsed() < 500) {
|
|
||||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(m_core && m_core->authService()) {
|
|
||||||
m_core->authService()->logout();
|
|
||||||
}
|
|
||||||
qApp->quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1045,6 +1030,46 @@ void MainWindow::navigateToLogin() {
|
|||||||
fadeIn->start(QAbstractAnimation::DeleteWhenStopped);
|
fadeIn->start(QAbstractAnimation::DeleteWhenStopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::requestApplicationQuit()
|
||||||
|
{
|
||||||
|
if (m_quitPending) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_quitPending = true;
|
||||||
|
m_realQuit = true;
|
||||||
|
const bool stoppedPlayback = stopActivePlaybackForQuit();
|
||||||
|
if (stoppedPlayback) {
|
||||||
|
QTimer::singleShot(500, this, &MainWindow::finishApplicationQuit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
finishApplicationQuit();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWindow::stopActivePlaybackForQuit()
|
||||||
|
{
|
||||||
|
if (!m_homeView) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *player = m_homeView->activePlayerView();
|
||||||
|
if (!player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
player->stopAndReport();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::finishApplicationQuit()
|
||||||
|
{
|
||||||
|
if (m_core && m_core->authService()) {
|
||||||
|
m_core->authService()->logout();
|
||||||
|
}
|
||||||
|
qApp->quit();
|
||||||
|
}
|
||||||
|
|
||||||
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
|
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
|
||||||
{
|
{
|
||||||
if (watched == qApp && event->type() == QEvent::ApplicationStateChange) {
|
if (watched == qApp && event->type() == QEvent::ApplicationStateChange) {
|
||||||
@@ -1172,15 +1197,10 @@ void MainWindow::closeEvent(QCloseEvent *event)
|
|||||||
hide();
|
hide();
|
||||||
event->ignore();
|
event->ignore();
|
||||||
} else {
|
} else {
|
||||||
|
if (!m_quitPending) {
|
||||||
if (auto *player = m_homeView->activePlayerView()) {
|
requestApplicationQuit();
|
||||||
player->stopAndReport();
|
event->ignore();
|
||||||
|
return;
|
||||||
QElapsedTimer wait;
|
|
||||||
wait.start();
|
|
||||||
while (wait.elapsed() < 500) {
|
|
||||||
QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ protected:
|
|||||||
void closeEvent(QCloseEvent *event) override;
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void requestApplicationQuit();
|
||||||
|
bool stopActivePlaybackForQuit();
|
||||||
|
void finishApplicationQuit();
|
||||||
void setupGlobalSearchHistory();
|
void setupGlobalSearchHistory();
|
||||||
void hideGlobalSearchTransientUi();
|
void hideGlobalSearchTransientUi();
|
||||||
void updateGlobalSearchCompleter(const QString &text = QString());
|
void updateGlobalSearchCompleter(const QString &text = QString());
|
||||||
@@ -59,6 +62,7 @@ private:
|
|||||||
bool m_themeAnimating{false};
|
bool m_themeAnimating{false};
|
||||||
bool m_wasPausedByTray{false};
|
bool m_wasPausedByTray{false};
|
||||||
bool m_viewTransitionInProgress{false};
|
bool m_viewTransitionInProgress{false};
|
||||||
|
bool m_quitPending{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user