Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

player: coalesce option updates and drop redundant ones #15828

Merged
merged 2 commits into from
Feb 17, 2025

Conversation

Dudemanguy
Copy link
Member

Could use some more testing for sure, but it seems like the dumb way of just processing these in the playloop does the trick.

Stuff like input-commands or hwdec are good to test since it's obvious if those do repeated executions. e.g. consider these config files.

hwdec=auto
hwdec=auto-safe
hwdec=auto
hwdec=auto-safe
hwdec=auto
hwdec=auto-safe
hwdec=auto
hwdec=auto-safe
input-commands=loadfile ${options}${playlist/0}${playlist/0}${playlist/0}
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a
input-commands-pre=a

Load them at runtime with load-config-file. On master, the first one spams the terminal with garbage because of constant probing. The second one freezes the player and probably will OOM. With this PR, only the last hwdec is processed on the first config file and the second one just quits the player since you're giving loadfile garbage.

Bonus:

input-commands=show-text b
input-commands-append=show-text a
input-commands-append=show-text a
input-commands-append=show-text a

Results in this on master:

[   4.947][v][cplayer] Setting option 'input-commands' = 'show-text b' (flags = 4)
[   4.947][v][cplayer] Setting option 'input-commands-append' = 'show-text a' (flags = 4)
[   4.966][v][cplayer] Setting option 'input-commands-append' = 'show-text a' (flags = 4)
[   4.967][v][cplayer] Setting option 'input-commands-append' = 'show-text a' (flags = 4)
[   4.968][t][cplayer] Run command: show-text, flags=73, args=[text="b", duration="-1", level="0"]
[   4.968][t][cplayer] Run command: show-text, flags=73, args=[text="b", duration="-1", level="0"]
[   4.969][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]
[   4.969][t][cplayer] Run command: show-text, flags=73, args=[text="b", duration="-1", level="0"]
[   4.970][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]
[   4.971][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]
[   4.971][t][cplayer] Run command: show-text, flags=73, args=[text="b", duration="-1", level="0"]
[   4.972][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]
[   4.972][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]
[   4.973][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]

With this PR:

[   1.360][v][cplayer] Setting option 'input-commands' = 'show-text b' (flags = 4)
[   1.361][v][cplayer] Setting option 'input-commands-append' = 'show-text a' (flags = 4)
[   1.361][v][cplayer] Setting option 'input-commands-append' = 'show-text a' (flags = 4)
[   1.362][v][cplayer] Setting option 'input-commands-append' = 'show-text a' (flags = 4)
[   1.363][t][cplayer] video_output_image: r=2/eof=0/st=playing
[   1.363][t][cplayer] s=1.000950 vsyncs=3 dur=0.041708 ratio=2.500000 err=-0.00833375002083428656 (-0.500000/-0.200000)
[   1.363][t][cplayer] frametime=0.041
[   1.366][t][cplayer] Run command: show-text, flags=73, args=[text="b", duration="-1", level="0"]
[   1.366][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]
[   1.366][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]
[   1.366][t][cplayer] Run command: show-text, flags=73, args=[text="a", duration="-1", level="0"]

For some reason, mp_option_change_callback had weird special logic on
init to start the ipc client. This makes no sense. It should just be
started in mp_initialize like all the other clients.
Copy link

github-actions bot commented Feb 8, 2025

Download the artifacts for this pull request:

Windows
macOS

player/command.c Outdated Show resolved Hide resolved
player/playloop.c Outdated Show resolved Hide resolved
player/command.c Outdated Show resolved Hide resolved
player/command.c Outdated Show resolved Hide resolved
Copy link
Contributor

@kasper93 kasper93 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle it make sense. I didn't think hard about corner cases that it might produce, but the change is not invasive, so we can monitor the impact.

And overall this is nice optimization if for whatever reason some option is spammed to be updated.

The big option callback in player/command will trigger on every single
update. This is not so great when several heavy option changes are
called in rapid succession and operations are pointlessly repeated. Try
to copy the approach that input commands do and run the actual callbacks
during the playloop. This is not really a smart or sophisticated
mechanism. It also only works for the main option cache. In theory,
other option caches like vo_opts could get spammed too and this makes no
attempt on those. But regardless, this is probably good enough for us.
mp_option_change_callback now tries to group together any new callbacks
with existing unprocessed ones and drop redundant ones whenever
something new arrives.
@kasper93
Copy link
Contributor

Should we document it? Not sure where. But option callback won't be immediate now. So I wonder if it is not a problem. Say someone do enable option x, run command, disable option x. What option state the command will see?

@Dudemanguy
Copy link
Member Author

Dudemanguy commented Feb 16, 2025

I did a few crude tests fully expecting it to break something but it didn't. Probably still needs some more testing to see if it does something unexpected.

@na-na-hi
Copy link
Contributor

One issue is that many of the functions called in the option change callback do nothing when the option value is not changed. Example:

if ((*pid > 0) != enable) {

Which means if the option is changed to another value before changing it back to the original value, it would do nothing, instead of reloading the script.

There are many other examples of this value change detection:

if (internal_paused != mpctx->paused) {

I don't know how this will affect usage in practice, but there are many things handled inside this callback so the potential change in behavior is high.

@kasper93
Copy link
Contributor

I don't know how this will affect usage in practice, but there are many things handled inside this callback so the potential change in behavior is high.

Yes, this is pretty clear that some sequence of events may not occur. This is what this change suppose to fix. Like we can read in PR description.

hwdec=auto
hwdec=auto-safe
hwdec=auto
hwdec=auto-safe
hwdec=auto
hwdec=auto-safe
hwdec=auto
hwdec=auto-safe

will no longer rapidly change hwdec, possibly reinitializing whole VO. Same with your pause example.

The change has impact for sure, but like I said previously I'm not sure what corner cases it can trigger in real usage. I mean it is hard to imagine someone depends on behavior of executing commands in real time manner.

@Dudemanguy
Copy link
Member Author

Dudemanguy commented Feb 17, 2025

Internally, the option values do still change with this. So for a command that is like set property to a; do something; set property to b, the do something will operate as if the value of property is a. What will not happen, of course, is the callback. I don't know if something would specifically be dependent something in the callback part running.

As for clients, we already actually coalesce notification for property/option changes. If something changes the value of a property a bunch of times in a row, the observer will only see the latest change. This PR does not change the behavior there. So I think the potential impact is probably pretty low but again hard to predict since we have so many options that interact in so many ways.

@Dudemanguy Dudemanguy added this pull request to the merge queue Feb 17, 2025
Merged via the queue into mpv-player:master with commit bbac628 Feb 17, 2025
26 checks passed
@Dudemanguy Dudemanguy deleted the option-coalescing branch February 17, 2025 16:33
@verygoodlee
Copy link
Contributor

verygoodlee commented Feb 17, 2025

Windows

This breaks --force-window on Windows 10/11.

  • run mpv --force-window=immediate --idle.
    there's a black window appears and immediately disappears, and then the mpv window appears, but not focused.

@Dudemanguy
Copy link
Member Author

Dudemanguy commented Feb 17, 2025

Well that was fast. Neither of those options even run callbacks so I'm not sure how it's even possible. Investigating...

Edit: Turned out to be a small miss.

kasper93 added a commit to kasper93/mpv that referenced this pull request Feb 17, 2025
PR mpv-player#15457 has not been rebased after merge of mpv-player#15828 resulting in type
mismatch.

Fixes: f57c0af
github-merge-queue bot pushed a commit that referenced this pull request Feb 17, 2025
PR #15457 has not been rebased after merge of #15828 resulting in type
mismatch.

Fixes: f57c0af
Dudemanguy added a commit to Dudemanguy/mpv that referenced this pull request Feb 17, 2025
The refactoring in bbac628 missed that
the initial update handler didn't immediately run all the triggered
callbacks but would instead delay it until the next playloops. This
subtly breaks things of course like hooks, force window handling, etc.
Ensure that we immediately run all the callbacks like before on startup.

Fixes bbac628
Fixes mpv-player#15828 (comment)
Dudemanguy added a commit to Dudemanguy/mpv that referenced this pull request Feb 17, 2025
The refactoring in bbac628 missed that
the initial update handler didn't immediately run all the triggered
callbacks but would instead delay it until the next playloop. This
subtly breaks things of course like hooks, force window handling, etc.
Ensure that we immediately run all the callbacks like before on startup.

Fixes bbac628
Fixes mpv-player#15828 (comment)
Dudemanguy added a commit that referenced this pull request Feb 17, 2025
The refactoring in bbac628 missed that
the initial update handler didn't immediately run all the triggered
callbacks but would instead delay it until the next playloop. This
subtly breaks things of course like hooks, force window handling, etc.
Ensure that we immediately run all the callbacks like before on startup.

Fixes bbac628
Fixes #15828 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants