Skip to content

Skip background grabber/blur while playing to avoid microstutters#73

Open
pannal wants to merge 1 commit into
sualfred:matrixfrom
pannal:fix-grabber-during-playback
Open

Skip background grabber/blur while playing to avoid microstutters#73
pannal wants to merge 1 commit into
sualfred:matrixfrom
pannal:fix-grabber-during-playback

Conversation

@pannal

@pannal pannal commented May 31, 2026

Copy link
Copy Markdown

While debugging microstutters on an Amlogic CoreELEC box during video playback, I traced single dropped frames back to this addon's service loop.

Service.start() calls grabfanart() every ~200s, which fires several synchronous JSON-RPC library queries (VideoLibrary.GetMovies/GetTVShows, AudioLibrary.GetArtists/GetMusicVideos), and it runs ImageBlur() (a PIL blur) on every tick. All of that runs on the service thread. On a weaker device the burst is enough to briefly starve the video render thread, and a frame gets dropped.

The log made it hard to argue with: the dropped frame landed in the same millisecond as the Start new fanart grabber process line.

These backgrounds aren't visible during fullscreen playback anyway, so the fix just defers the timed tasks until playback stops, by adding not xbmc.Player().isPlaying() to the existing screensaver guard.

One deliberate choice: I used isPlaying() rather than isPlayingVideo(). isPlayingVideo() can briefly read false during pauses and seek/transition states, which would let the grabber slip through and hitch playback right as it resumes. isPlaying() avoids that. The trade-off is that the backgrounds won't refresh during music playback either, but they catch up as soon as playback ends.

I left the version bump to you.

The service loop runs grabfanart() - several synchronous JSON-RPC library
queries - every ~200s, plus ImageBlur() every tick. On weaker devices this
briefly starves the video render thread and causes single-frame drops /
microstutters during playback. The backgrounds these feed aren't visible
during fullscreen playback, so gate the timed tasks on not Player().isPlaying().

isPlaying() (rather than isPlayingVideo()) is used so a brief pause or seek -
where isPlayingVideo() can momentarily read false - can't let the grabber slip
through and hitch playback on resume.
pannal added a commit to pannal/p3i_repo that referenced this pull request May 31, 2026
Ship the playback-gate fix on the latest upstream base (2.0.9) too, so users
already on upstream 2.0.9 receive it (Kodi installs the highest version; a
2.0.8-p3i.1-only repo would not win over a stock 2.0.9). 2.0.8-p3i.1 retained
as a minimal-delta fallback. Upstream PR: sualfred/script.embuary.helper#73
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.

1 participant