chore(mpv): share desktop startup options and stop forwarding unused Android events

Linux and Windows each wrote the same eleven pre-initialize mpv options
(keep-open, idle, input disabling, OSC, ytdl, audio fallback, and the
audio-only set); ApplyCommonStartupOptions in mpv_player_common.h owns
them once, with the ytdl security rationale kept in one place. Rendering,
windowing, HDR, and log-level options stay per platform.

The Android JNI event thread forwarded every mpv event to Kotlin, where
MpvEvent modelled ten variants but MpvPlayerCore consumes four. The
native switch now forwards only START_FILE, FILE_LOADED, and
PLAYBACK_RESTART (END_FILE keeps its own path), and the unused variants
are gone.
This commit is contained in:
edde746
2026-09-03 11:36:29 +02:00
parent b27cab4510
commit d181bd34ae
6 changed files with 46 additions and 68 deletions
@@ -537,7 +537,6 @@ class MpvPlayerCore private constructor(
delegate?.onEvent("file-loaded", null)
}
is MpvEvent.PlaybackRestart -> delegate?.onEvent("playback-restart", null)
else -> {}
}
}
}
+6 -1
View File
@@ -81,10 +81,15 @@ void* event_thread(void* arg) {
case MPV_EVENT_END_FILE:
sendEndFileToJava(env, mp_event);
break;
default:
case MPV_EVENT_START_FILE:
case MPV_EVENT_FILE_LOADED:
case MPV_EVENT_PLAYBACK_RESTART:
ALOGV("event: %s\n", mpv_event_name(mp_event->event_id));
sendEventToJava(env, mp_event->event_id);
break;
default:
// Nothing on the Kotlin side consumes the remaining ids (MpvEvent.fromId).
break;
}
}
@@ -1,30 +1,18 @@
package com.edde746.plezy.libmpv
sealed interface MpvEvent {
data object Shutdown : MpvEvent
data object StartFile : MpvEvent
data class EndFile(val reason: EndFileReason?) : MpvEvent
data object FileLoaded : MpvEvent
data object VideoReconfig : MpvEvent
data object AudioReconfig : MpvEvent
data object Seek : MpvEvent
data object PlaybackRestart : MpvEvent
data object QueueOverflow : MpvEvent
data class Other(val eventId: Int) : MpvEvent
companion object {
// Mirrors the ids event.cpp forwards; END_FILE arrives via its own JNI path.
internal fun fromId(id: Int): MpvEvent? = when (id) {
1 -> Shutdown
6 -> StartFile
8 -> FileLoaded
17 -> VideoReconfig
18 -> AudioReconfig
20 -> Seek
21 -> PlaybackRestart
24 -> QueueOverflow
// 0=NONE, 2=LOG_MESSAGE, 7=END_FILE, 22=PROPERTY_CHANGE handled separately
0, 2, 7, 22 -> null
else -> Other(id)
else -> null
}
}
}
+4 -25
View File
@@ -333,23 +333,14 @@ bool MpvPlayer::Initialize() {
return false;
}
if (audio_only_) {
// Music core: no VO, no video decode. vid=no keeps embedded cover art
// from ever becoming a video track, and force-window/audio-display make
// sure mpv never opens a video output for it either.
mpv_set_option_string(mpv_, "vid", "no");
mpv_set_option_string(mpv_, "force-window", "no");
mpv_set_option_string(mpv_, "audio-display", "no");
mpv_set_option_string(mpv_, "gapless-audio", "weak");
} else {
plezy::mpv_common::ApplyCommonStartupOptions(mpv_, audio_only_);
mpv_set_option_string(mpv_, "terminal", "no");
if (!audio_only_) {
// Configure mpv for embedded playback.
mpv_set_option_string(mpv_, "vo", "libmpv");
mpv_set_option_string(mpv_, "hwdec", "auto");
}
mpv_set_option_string(mpv_, "keep-open", "yes");
mpv_set_option_string(mpv_, "audio-fallback-to-null", "yes");
if (!audio_only_) {
// hdr-compute-peak is nested under the same predicate as the tone-map pass -
// it runs exactly when the source's declared peak exceeds target-peak - so it
// costs nothing while the compositor owns tone mapping and gives
@@ -364,18 +355,6 @@ bool MpvPlayer::Initialize() {
// `hdr-enabled` write puts here through SetHDREnabled.
mpv_set_option_string(mpv_, "target-colorspace-hint", plezy::mpv_common::TargetColorspaceHint(hdr_enabled_));
}
mpv_set_option_string(mpv_, "idle", "yes");
mpv_set_option_string(mpv_, "input-default-bindings", "no");
mpv_set_option_string(mpv_, "input-vo-keyboard", "no");
mpv_set_option_string(mpv_, "osc", "no");
mpv_set_option_string(mpv_, "terminal", "no");
// Every URL Plezy opens is a media-server stream or a local file, never a
// site mpv's bundled ytdl_hook could resolve. Loading it costs an on_load
// hook per open and, on a failed open, spawns yt-dlp with the full stream
// URL — access token included — in its argv, where /proc exposes it. mpv
// gates loading the builtin script on this option at mpv_initialize time,
// so it has to be set here rather than from Dart.
mpv_set_option_string(mpv_, "ytdl", "no");
// Default to info-level logging. The vaapi hwdec probe and the "Using
// software decoding" fallback are MSGL_INFO messages, and both are the only
+31
View File
@@ -370,6 +370,37 @@ inline bool ParseEnabledFlag(const std::string& value) { return value == "yes" |
inline const char* TargetColorspaceHint(bool hdr_enabled) { return hdr_enabled ? "auto" : "no"; }
// Startup options shared by every desktop mpv core. Must run between
// mpv_create() and mpv_initialize(); platform-specific options (vo, hwdec,
// wid, HDR/tone-mapping, log level) stay with the caller.
inline void ApplyCommonStartupOptions(mpv_handle* mpv, bool audio_only) {
if (audio_only) {
// Music core: no VO, no video decode. vid=no keeps embedded cover art
// from ever becoming a video track, and force-window/audio-display make
// sure mpv never opens a video output for it either.
mpv_set_option_string(mpv, "vid", "no");
mpv_set_option_string(mpv, "force-window", "no");
mpv_set_option_string(mpv, "audio-display", "no");
mpv_set_option_string(mpv, "gapless-audio", "weak");
}
mpv_set_option_string(mpv, "keep-open", "yes");
// When the audio device becomes unavailable (sleep, device unplug), fall
// back to the null audio output instead of permanently dropping the audio
// track. Recovery is handled by the platform event loop.
mpv_set_option_string(mpv, "audio-fallback-to-null", "yes");
mpv_set_option_string(mpv, "idle", "yes");
mpv_set_option_string(mpv, "input-default-bindings", "no");
mpv_set_option_string(mpv, "input-vo-keyboard", "no");
mpv_set_option_string(mpv, "osc", "no");
// Every URL Plezy opens is a media-server stream or a local file, never a
// site mpv's bundled ytdl_hook could resolve. Loading it costs an on_load
// hook per open and, on a failed open, spawns yt-dlp with the full stream
// URL — access token included — in its argv, where other processes can read
// it. mpv gates loading the builtin script on this option at mpv_initialize
// time, so it has to be set here rather than from Dart.
mpv_set_option_string(mpv, "ytdl", "no");
}
enum class AudioReloadReason { kNone, kResume, kNullFallback };
struct AudioReloadAction {
+3 -27
View File
@@ -564,16 +564,9 @@ bool MpvPlayer::Initialize(HWND view) {
return false;
}
if (audio_only_) {
// Windowless music core: no HWND, no VO, no video decode. vid=no keeps
// embedded cover art from ever becoming a video track, and
// force-window/audio-display make sure mpv never opens a video output
// for it either.
mpv_set_option_string(mpv_, "vid", "no");
mpv_set_option_string(mpv_, "force-window", "no");
mpv_set_option_string(mpv_, "audio-display", "no");
mpv_set_option_string(mpv_, "gapless-audio", "weak");
} else {
plezy::mpv_common::ApplyCommonStartupOptions(mpv_, audio_only_);
if (!audio_only_) {
// Create a child window for mpv to render into, parented to the Flutter
// |view|. The video child then sits in the view's own per-window layer
// stack, above the view's (never-painted) layer-1 content and below the
@@ -604,21 +597,9 @@ bool MpvPlayer::Initialize(HWND view) {
// hwdec is set from Flutter via setProperty based on user preference
}
// Configure mpv for embedded playback.
mpv_set_option_string(mpv_, "keep-open", "yes");
mpv_set_option_string(mpv_, "idle", "yes");
mpv_set_option_string(mpv_, "input-default-bindings", "no");
mpv_set_option_string(mpv_, "input-vo-keyboard", "no");
// Hardware media keys are owned by the SMTC integration (os_media_controls);
// mpv's default handling would double-handle Play/Pause.
mpv_set_option_string(mpv_, "input-media-keys", "no");
mpv_set_option_string(mpv_, "osc", "no");
// Never resolve URLs through mpv's bundled ytdl_hook: Plezy only ever opens
// media-server streams and local files, the hook adds a per-open on_load
// round trip, and on a failed open it spawns yt-dlp with the access token in
// its argv. mpv decides whether to load the builtin script during
// mpv_initialize, so this must be an option, not a Dart setProperty.
mpv_set_option_string(mpv_, "ytdl", "no");
if (!audio_only_) {
// Let mpv use display/context detection instead of forcing HDR signaling.
@@ -639,11 +620,6 @@ bool MpvPlayer::Initialize(HWND view) {
}
}
// When WASAPI becomes unavailable (sleep, device unplug), fall back to null
// audio output instead of permanently dropping the audio track. Recovery is
// handled by MaybeRunAudioRecovery in the event loop.
mpv_set_option_string(mpv_, "audio-fallback-to-null", "yes");
// Default to warn-level logging; Dart side can raise to "v" if debug logging is enabled.
mpv_request_log_messages(mpv_, "warn");