fix: refine playback shutdown and danmaku sizing

This commit is contained in:
dela
2026-06-21 21:59:54 +08:00
parent cf58267d41
commit 4fcfde8be3
6 changed files with 129 additions and 52 deletions
+1 -1
View File
@@ -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')
+9 -2
View File
@@ -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
+47 -27
View File
@@ -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,16 +1197,11 @@ 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();
} }
} }
+4
View File
@@ -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