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