Leserartikel KODi: automatische Bildwiederholfrequenz unter Wayland und KDE für lokale Medien

Spassmuskel

Lt. Commander
Registriert
Mai 2013
Beiträge
1.251
Hallo zusammen,

vorab: sollte es für das weiter unten geschilderte Problem mit Kodi und Wayland schon eine Lösung geben, dann nur her damit. Ich konnte leider nichts finden. Das System welches ich verwendet habe ist Kubuntu 24.04 LTS.

Sollte der Artikel auf Interesse stoßen, kann ich das Ganze noch mit Bilder untermauern. Hatte jetzt ehrlich gesagt keine Lust dazu. :D

Was ist das generelle Problem?
Unter Wayland ist es leider nicht mehr möglich mit Kodi die Option "Bildwiederholfrequenz anpassen" zu nutzen (https://github.com/xbmc/xbmc/issues/20614). Neue Lösungen schlagen VRR vor, was ich aber aufgrund des Alters meines TVs nicht testen kann.
Das heißt, dass jedes Video immer mit derselben Bildfrequenz ausgegeben wird. Spiele ich ein Video mit 25p (typisch für DVD oder auch TV Aufnahmen) und die Bildfrequenz ist im System auf 60 Hz, ruckelt das Video, da 60 kein gerades Vielfaches von 25 ist.
Unter X11 (aber auch in Windows Universum) kann Kodi automatisch je nach Inhalt die Bildwiederholrate des Bildschirms anpassen. Unter Wayland ist das nicht mehr gewünscht und anscheinend nicht implementierbar. Man müsste nun jedes Mal in den Systemeinstellungen die richtige Bildfrequenz passend zum abgespielten Video einstellen.

Welche Stolpersteine gibt es, wenn man die Bildrate manuelle ändert?
Zumindest unter KDE werden in den Einstellungen leider nicht alle möglichen Bildwiederholfrequenzen angezeigt. Es gibt nämlich einen Unterschied zwischen 24 Hz und 23,976 Hz. Die meisten Kinofilme nutzen 23,976 Hz. Nur wenige genau 24 Hz. Leider ist die Differenz beim Abspielen von Videos bemerkbar und ein Video mit einer Bildrate von 23,976 würde bei einer Hz-Ausgabe von 24 ca. alle 40 Sekunden kurz Ruckeln.
KDE rundet einfach alle möglichen Frequenzen, sodass unter kscreen-doctor -o bei meinem TV bspw. zwei Mal 1920x1080@24 als Modi (in dem Fall Modi 5 und 6) steht. Eines der beiden Einträge ist allerdings die Frequenz mit 23,976 Hz. In der GUI gibt es aber nur 24 Hz (unter Windows wird bspw. zwischen 23 und 24 unterschieden), sodass immer genau 24 Hz ausgegeben werden. Das heißt, nicht einmal manuell in der GUI kann ich schnell die Bildfrquenz passend zum Medium ändern.
Mit kscreen-doctor in der Konsole kann ich allerdings 23,976 Hz erzwingen (leider nicht benutzerfreundlich und für mich mittlerweile typisch für Linux...kscreen-doctor output.1.mode.6). Das gleiche übrigens auch bei 1920x1080@60. Hier gibt es auch Unterschiede: einmal genau 60Hz und das andere wäre 59,94 Hz (NTSC). Auch diese Option gibt es nicht in der GUI

Lösungsansatz:
Die Lösung stammt ehrlicherweise nicht von mir, sondern vom Copilot. Aber sie funktioniert für meine Zwecke ganz gut:
Mir wurde ein Python Skript vorgeschlagen, welches mittels der JSON-RPC API prüft, ob ein Video abgespielt wird und dann mittels kscreen-doctor die Bildrate von Kubuntu auf die des Videos ändert. Hierzu erhält man von Kodi den Pfad der abgespielten Datei und mittels ffmpeg werden die Eigenschaften ausgelesen und dann von kscreen-doctor die Bildrate umgestellt. Wenn das Video beendet wird, wird die Bildrate wieder auf einen Standard (bei mit 1920x1080@60) umgestellt.
Die Überprüfung erfolgt alle 2 Sekunden.
Das ganze ist dann noch in einem Skript eingebettet, welches erst Kodi startet und dann das Python Skript, sodass beides mit Doppelklick aufrufbar ist.

Voraussetzungen für die Lösung:


  • Kodi als Flatpak installiert
  • es muss in Kodi die Steuerung per http aktiviert sein https://kodi.wiki/view/Web_interface (aus Gründen der Sicherheit mit Passwort)
  • ffmpeg muss installiert sein
  • die Medien müssen lokal vorhanden sein (ext./int. Festplatte, wahrscheinlich geht es auch innerhalb des Netzwerkes--> konnte ich nicht testen)
  • es muss KDE sein, da wir hier mit kscreen-doctor arbeiten, geht bestimmt auch mit anderen Tools unter anderen Oberflächen
  • Python solle ausführbar sein

Einschränkungen:
  • funktioniert bisher nur mit lokalen Medien. Ich habe es nicht geschafft mittels der API gleich die Videodaten zu bekommen. Evtl. schafft es ein anderer ;)
  • bei ein paar älteren Videos mit Container .TS hat ffmpeg anscheinend Probleme die Infos zu extrahieren. Bei allen anderen hat es aber funktioniert. Möchte deshalb nicht ausschließen, dass andere Formate evtl. auch Probleme machen



Hier erstmal das Python Skript:
Python:
import subprocess
import time
import os
import requests
from requests.auth import HTTPBasicAuth

CHECK_INTERVAL = 2
LAST_VIDEO_LABEL = None

# 🔑 Kodi Login-Daten
KODI_USER = "BENUTZERNAME"
KODI_PASS = "PASSWORT"
KODI_URL = "http://localhost:8080/jsonrpc"

def get_active_player():
    try:
        output = subprocess.check_output(["playerctl", "-l"]).decode().strip().split('\n')
        for player in output:
            status = subprocess.check_output(["playerctl", "-p", player, "status"]).decode().strip()
            if status == "Playing":
                return ("playerctl", player)
    except Exception:
        pass

    try:
        payload = {
            "jsonrpc": "2.0",
            "method": "Player.GetActivePlayers",
            "id": 1
        }
        r = requests.post(KODI_URL, json=payload, auth=HTTPBasicAuth(KODI_USER, KODI_PASS)).json()
        if r.get("result"):
            return ("kodi", r["result"][0]["playerid"])
    except Exception:
        pass

    return (None, None)

def get_video_label(source, player_id):
    if source == "playerctl":
        try:
            return subprocess.check_output(["playerctl", "-p", player_id, "metadata", "xesam:title"]).decode().strip()
        except Exception:
            return None
    elif source == "kodi":
        try:
            # Schritt 1: Player.GetItem → movieid holen
            payload = {
                "jsonrpc": "2.0",
                "method": "Player.GetItem",
                "params": {"playerid": player_id},
                "id": 2
            }
            r = requests.post(KODI_URL, json=payload, auth=HTTPBasicAuth(KODI_USER, KODI_PASS)).json()
            item = r.get("result", {}).get("item", {})
            movie_id = item.get("id")

            # Schritt 2: VideoLibrary.GetMovieDetails → file holen
            if movie_id and item.get("type") == "movie":
                payload = {
                    "jsonrpc": "2.0",
                    "method": "VideoLibrary.GetMovieDetails",
                    "params": {"movieid": movie_id, "properties": ["file"]},
                    "id": 3
                }
                r = requests.post(KODI_URL, json=payload, auth=HTTPBasicAuth(KODI_USER, KODI_PASS)).json()
                return r.get("result", {}).get("moviedetails", {}).get("file")
        except Exception:
            return None
    return None

def get_framerate_from_file(file_path):
   
    try:
        output = subprocess.check_output([
            "ffprobe", "-v", "0", "-select_streams", "v:0",
            "-show_entries", "stream=r_frame_rate",
            "-of", "default=noprint_wrappers=1:nokey=1", file_path
        ]).decode().strip()
        num, denom = map(int, output.split('/'))
        return round(num / denom, 3)
    except Exception:
        return None

def set_refresh_rate(fps):
    if 23.95 <= fps <= 23.98:
        print("🔄 Wechsel zu 23.976 Hz (mode 6)")
        subprocess.run(["kscreen-doctor", "output.1.mode.6"])
    elif 23.99 <= fps <= 24.01:
        print("🔄 Wechsel zu 24.000 Hz (mode 5)")
        subprocess.run(["kscreen-doctor", "output.1.mode.5"])
    elif fps == 25:
        subprocess.run(["kscreen-doctor", "output.1.mode.3"])
    elif fps == 30:
        subprocess.run(["kscreen-doctor", "output.1.mode.0"])
    elif fps == 50:
        subprocess.run(["kscreen-doctor", "output.1.mode.3"])
    elif 59.0 <= fps <= 59.9999:
        subprocess.run(["kscreen-doctor", "output.1.mode.2"])
    elif fps == 60:
        subprocess.run(["kscreen-doctor", "output.1.mode.0"])
    else:
        print(f"⚠️ Keine passende Bildrate für {fps} fps gefunden.")

def main():
    global LAST_VIDEO_LABEL
    video_mode_set = False

    while True:
        source, player_id = get_active_player()

        if source is None:
            if video_mode_set:
                print("\n🛑 Kein Video — zurück zu 60 Hz")
                subprocess.run(["kscreen-doctor", "output.1.mode.0"])
                video_mode_set = False
                LAST_VIDEO_LABEL = None
            else:
                print("⏳ Kein aktiver Player.")
            time.sleep(CHECK_INTERVAL)
            continue

        file_path = get_video_label(source, player_id)
        if file_path and file_path != LAST_VIDEO_LABEL:
            LAST_VIDEO_LABEL = file_path
            print(f"\n📺 Neues Video: {file_path}")
            if os.path.isfile(file_path):
                fps = get_framerate_from_file(file_path)
                if fps:
                    set_refresh_rate(fps)
                    video_mode_set = True
                else:
                    print("🚫 Framerate nicht ermittelbar.")
            else:
                print("❌ Datei existiert nicht oder kein Zugriff.")
        time.sleep(CHECK_INTERVAL)

if __name__ == "__main__":
    main()

Und hier das Startskript mit KODi Start und automatischem abrufen vom Python Code
Code:
#!/bin/bash

echo "🚀 Starte Kodi (Flatpak)..."
flatpak run tv.kodi.Kodi &
KODI_PID=$!

echo "🧠 Starte Python-Skript..."
python3 ~/Dokumente/kodi_framerate_switcher_debug.py &
SCRIPT_PID=$!

# ⏳ Warte, bis Kodi beendet wird
echo "⏳ Warte auf das Ende von Kodi..."
wait $KODI_PID

echo "🛑 Kodi wurde beendet — beende Python-Skript..."
kill $SCRIPT_PID

# 🔄 Optional: Zurück zu 60 Hz
kscreen-doctor output.1.mode.0

Anpassen:
Angepasst werden muss in den ersten Zeilen der Benutzername und das Kennwort, welches ihr in Kodi für die http Steuerung vergeben habt:
Code:
# 🔑 Kodi Login-Daten
KODI_USER = "BENUTZERNAME"
KODI_PASS = "PASSWORT"

Ihr müsst die richtigen Modi und den Output für euren Bildschirm eintragen, damit kscreen-doctor die richtige Bildwiederholfrequenz einträgt.
Alle Modi erhaltet ihr mit dem Befehl:
Code:
kscreen-doctor -o
.
Aufpassen: wie schon im Einleitungstext geschrieben, rundet KDE einfach alle Frequenzen. Um auch die Ungeraden richtig einzutragen, müsst ihr es ausprobieren. Auslesbar per:
Code:
wayland-info | grep -i refresh

Die Modi (output.1.mode.6 , wäre in dem Fall Modi 6) müsst ihr dann hier in der Funktion für euch einstellen.
Code:
def set_refresh_rate(fps):
    if 23.95 <= fps <= 23.98:
        print("🔄 Wechsel zu 23.976 Hz (mode 6)")
        subprocess.run(["kscreen-doctor", "output.1.mode.6"])
    elif 23.99 <= fps <= 24.01:
        print("🔄 Wechsel zu 24.000 Hz (mode 5)")
        subprocess.run(["kscreen-doctor", "output.1.mode.5"])
    elif fps == 25:
        subprocess.run(["kscreen-doctor", "output.1.mode.3"])
    elif fps == 30:
        subprocess.run(["kscreen-doctor", "output.1.mode.0"])
    elif fps == 50:
        subprocess.run(["kscreen-doctor", "output.1.mode.3"])
    elif 59.0 <= fps <= 59.9999:
        subprocess.run(["kscreen-doctor", "output.1.mode.2"])
    elif fps == 60:
        subprocess.run(["kscreen-doctor", "output.1.mode.0"])
    else:
        print(f"⚠️ Keine passende Bildrate für {fps} fps gefunden.")



Standardfrequenz einstellen:
Zu diesem Bildmodi kehrt das Sysdtem zurück, wenn kein Video abgespielt wird:
Code:
def main():
    global LAST_VIDEO_LABEL
    video_mode_set = False

    while True:
        source, player_id = get_active_player()

        if source is None:
            if video_mode_set:
                print("\n🛑 Kein Video — zurück zu 60 Hz")
                subprocess.run(["kscreen-doctor", "output.1.mode.0"])
                video_mode_set = False
                LAST_VIDEO_LABEL = None
            else:
                print("⏳ Kein aktiver Player.")
            time.sleep(CHECK_INTERVAL)
            continue

In start_kodi_and_script.sh muss noch der Dateipfad für euer Python Skript angepasst werden:
Code:
python3 ~/Dokumente/kodi_framerate_switcher_debug.py &

und nochmal die Standardfrequenz, wenn Kodi geschlossen wird:
Code:
# 🔄 Optional: Zurück zu 60 Hz
kscreen-doctor output.1.mode.0

Evtl. hilft das dem ein oder anderen oder es gibt Verbesserungsvorschläge, wie man es einfacher gestalten kann.
Hoffe es war verständlich ;)

Habe den Artikel recht schnell geschrieben, deswegen ignoriert bitte erstmal alle Rechtschreib- und Grammatikfehler. :D
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Metalveteran, SpiII, Kaito Kariheddo und 2 andere
Spassmuskel schrieb:
Unter X11 (aber auch in Windows Universum) kann Kodi automatisch je nach Inhalt die Bildwiederholrate des Bildschirms anpassen.
Bist du dir da sicher?

Ich kann mich nicht erinnern, dass bei mir ein Medienabspieler jemals die Bildwiederholfrequenz an die Video-fps angepasst hat. Zumindest die Monitore, die ich hatte, haben bei jeder Auflösungs- und Hz-Änderung das entsprechend per OSD angezeigt.

Ich habe auch nie alle 40 Sekunden oder so ein Ruckeln gesehen, weil das Video mit 23,976 statt 24 fps läuft. Hier würde ja ein Frame doppelt angezeigt werden - für ~0,0417 s bzw. 2x hintereinander für insgesamt ~0,083 s. Also zumindest mir fällt das nicht auf.
 
@Krik ja, unter X11 geht das definitiv (funktioniert bspw. wenn ich Kubuntu mit einer X11 Session starte). Ich nutze Kodi aber auch nur an meinem Zweitrechner am TV. Ich kann dir also nicht sagen, ob das Verhalten bei Monitoren anders ist. Da habe ich es nie benutzt.

Ich teste nun seit Monaten Linux (zuvor Ubuntu mit Gnome) und konnte Wayland wegen meiner nvidia Karte nie wirklich nutzen. Seit ein paar Tagen habe ich eine AMD Karte im Rechner und kann Wayland mal normal ausprobieren. Das war das erste was mir aufgefallen ist, da es bisher out of the box gelaufen ist.

In Kodi ist die Funktion hier im Menü versteckt https://kodi.wiki/view/Settings/Player/Videos#Adjust_display_refresh_rate und ist als Standard deaktiviert. Unter Wayland geht das nicht mehr.

Ich habe gestern auch ein Video mit 23,976 abgespielt und in der GUI auf 24 Hz gestellt und hatte alle paar Sekunden ein leichtes Ruckeln. Ansonsten lief es aber flüssig (bin allerdings auch recht empfindlich was das betrifft).
Manchmal wird es aber auch vom TV ausgeglichen. Bei einem Sony W805C (Einstellung Filmmodus auf hoch) konnte ich letztens beobachten, dass das Bild trotz 60Hz und 24p Wiedergabe flüssig läuft. Neuere Geräte können das kompensieren, mein oller Sony EX725 gehört da aber nicht dazu.
Wenn man bei manchen Geräten 24 Hz eingestellt, ist es auch oft 23,976 Hz (in Windows heißt es dann oft 23,98 oder nur 23).

Meiner Meinung nach ist das Thema komplizierter als es eigentlich sein sollte. Finde es auch sehr unverständlich warum mein Bluray Player von 2009 die Bildwiederholfrequenz automatisch richtig umstellen kann und neuere Geräte das gar nicht können oder es generell kein Standard ist.
 
Warum stellst du die Wiederholfrequenz des Monitors/TVs eigentlich auf 24 Hz? Bei 120 Hz wird jedes Frame nur 0,0083 s angezeigt. Wenn da mal eines aufgrund der krummen Fps sechs- statt fünffach in Folge dargestellt wird, sollte das für das bloße Augen quasi unsichtbar sein.
 
@Krik mein TV nimmt keine Bildwiederholrate von 120Hz entgegen (120Hz bei einem TV sind was anderes als bei einem Monitor. Erst neuere TVs können mit 120Hz -Ausgabe betrieben werden, ältere Modelle interpolieren nur die Bilder auf 100Hz). Es gehen nur maximal 60Hz. Er interpoliert die Frames ja nur. Das ist üblich bei älteren TVs...

Zudem stellt sich mir dann auch die Frage, ob die heutigen TVs ihre Zwischenbildberechnung bei einem nativem 120 Hz Signal überhaupt noch anwenden (in dem Fall würde jedes Frame ja nur mehrfach angezeigt werden). Man bräuchte hier ja dann ein 240 Hz Display um das Feature zu nutzen. Sprich dann hätte man dennoch das 24p Kinogeruckel. Würde ich also in dem Fall auch auf 24Hz umstellen. Außer man möchte den original Kinolook oder der TV unterstützt keine Zwischenbildberechnung oder hat 240Hz nativ (müsste so gut wie ausgestorben sein).
 
Zuletzt bearbeitet:
Spassmuskel schrieb:
Spiele ich ein Video mit 25p (typisch für DVD oder auch TV Aufnahmen) und die Bildfrequenz ist im System auf 60 Hz, ruckelt das Video, da 60 kein gerades Vielfaches von 25 ist.

Ich nutze seit einigen Monaten am TV einen kleinen MiniPC, auf dem ich Gentoo headless eingerichtet habe, darauf starte ich per SDDM Kodi in einer Wayland Sitzung. Das Bild wird per HDMI übertragen und damit ich ihn per Fernbedienung vom TV steuern kann habe ich dazwischen diesem CEC - HDMI Adapter von Pulse Eight dazwischen geklemmt.

Mein 55 Zoll Samsung TV zeigt mir bei diesem Setup auch alles in 60 Hertz an, bei mir hat noch nie etwas geruckelt.
 
Es geht hier nicht darum, dass ich eine grundlegende Problematik erkläre. Wenn es diversen Leuten nicht auffällt, schön.
Es geht hier um einen Ansatz wie man unter Wayland und KODi die Hz passend zum abgespielten Video automatisch umstellen kann.
Die grundsätzliche Problematik ist hier erklärt (vor allem Beitrag 4 und 6):
https://www.computerbase.de/forum/threads/bildwiederholfrequenz-und-ruckeln-bei-flat-tvs.1189285/

Ich möchte keine Grundsatzdiskussionen hier führen müssen. Und obige Aussagen sind hier einfach Fehl am Platz.
 
Zurück
Oben