Recent Posts

31
Allgemein [ General ] / Welche Video-Ausgabe für Hyperion?
« Last post by videopix on September 14, 2026, 00:45:57 »
Hallo Claus & Klaus,

danke für eure schnellen Antworten. Das Wiki bezieht sich auf Hardware-Grabber. Ich habe aber inzwischen eine schlanke Software-Lösung für mein System gefunden:

Bei mir läuft MLD 6.5 auf einem ASRock J3455M mit interner Intel-Grafik 500 und Ausgabe über softhddevice mit va-api HW-Beschleunigung, installiert über das Image "X86 PC mit Intel GPU".
Das Paket hyperion-ng setzt einen Podman-Container auf, hyperiond startete aber erst, nachdem ich in /usr/share/hyperion/docker-compose.yml ganz unten card0 durch card1 ersetzt hatte, also:
Code: [Select]
- /dev/dri/card1:/dev/dri/card1Bitte auch gleich das # vor privileged: true entfernen.

Das Hyperion UI war dann nach einem Reboot unter mld.fritz.box:8090 erreichbar.
Eigentlich sollte man dort unter "Aufnahme Hardware" die Grafik-Schnittstelle auswählen können. Das hat aber nicht funktioniert. Daher habe ich ein Python Script erstellt, das den Bildschirminhalt in einer niedrigen Auflösung abgreift und im Flatbuffer-Format an Hyperion schickt. Das funktioniert hier tadellos. Im Hyperion UI unter "Netzwerk" muss "Flatbuffer Server" aktiviert und der Port 19400 eingetragen sein. Speichern nicht vergessen!

Das Script habe ich als /usr/share/hyperion/vdr-kmsgrab-flatbuf.py abgelegt.

Inhalt:
Code: [Select]
#!/usr/bin/env python3

import subprocess
import socket
import struct
import time
import signal
import select

import flatbuffers


# ============================================================
# Konfiguration
# ============================================================

WIDTH = 160
HEIGHT = 90
FPS = 25

HYPERION_HOST = "127.0.0.1"
HYPERION_PORT = 19400

PRIORITY = 100
ORIGIN = "VDR-KMSgrab"

FRAME_SIZE = WIDTH * HEIGHT * 3

running = True


# ============================================================
# Signal handling
# ============================================================

def signal_handler(signum, frame):
    global running
    running = False


signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)


# ============================================================
# FlatBuffer
# ============================================================

def create_register(builder):
    origin = builder.CreateString(ORIGIN)

    builder.StartObject(2)

    builder.PrependUOffsetTRelativeSlot(
        0, origin, 0
    )

    builder.PrependInt32Slot(
        1, PRIORITY, 0
    )

    return builder.EndObject()


def create_raw_image(builder, frame):
    data = builder.CreateByteVector(frame)

    builder.StartObject(3)

    builder.PrependUOffsetTRelativeSlot(
        0, data, 0
    )

    builder.PrependInt32Slot(
        1, WIDTH, -1
    )

    builder.PrependInt32Slot(
        2, HEIGHT, -1
    )

    return builder.EndObject()


def create_image(builder, raw_image):
    builder.StartObject(3)

    # RawImage
    builder.PrependUint8Slot(
        0, 1, 0
    )

    builder.PrependUOffsetTRelativeSlot(
        1, raw_image, 0
    )

    builder.PrependInt32Slot(
        2, -1, -1
    )

    return builder.EndObject()


def create_request(builder, command_type, command):
    builder.StartObject(2)

    builder.PrependUint8Slot(
        0, command_type, 0
    )

    builder.PrependUOffsetTRelativeSlot(
        1, command, 0
    )

    return builder.EndObject()


def build_register():
    builder = flatbuffers.Builder(1024)

    register = create_register(builder)

    # Command.Register
    request = create_request(
        builder,
        4,
        register
    )

    builder.Finish(request)

    return builder.Output()


def build_image(frame):
    builder = flatbuffers.Builder(
        FRAME_SIZE + 1024
    )

    raw_image = create_raw_image(
        builder,
        frame
    )

    image = create_image(
        builder,
        raw_image
    )

    # Command.Image
    request = create_request(
        builder,
        2,
        image
    )

    builder.Finish(request)

    return builder.Output()


def build_clear():
    builder = flatbuffers.Builder(256)

    builder.StartObject(1)

    builder.PrependInt32Slot(
        0,
        PRIORITY,
        0
    )

    clear = builder.EndObject()

    # Command.Clear
    request = create_request(
        builder,
        3,
        clear
    )

    builder.Finish(request)

    return builder.Output()


# ============================================================
# TCP
# ============================================================

def send_message(sock, payload):
    header = struct.pack(
        ">I",
        len(payload)
    )

    sock.sendall(header)
    sock.sendall(payload)


def read_reply_nonblocking(sock, reply_buffer):
    """
    Hyperion Replies nebenbei abholen.

    Die Funktion blockiert nicht.
    """

    while True:

        try:
            data = sock.recv(65536)

            if not data:
                raise ConnectionError(
                    "Hyperion hat Verbindung geschlossen"
                )

            reply_buffer.extend(data)

        except BlockingIOError:
            break

    # Replies aus dem Buffer entfernen.
    #
    # Format:
    #   4 Byte Laenge
    #   Payload

    while True:

        if len(reply_buffer) < 4:
            break

        size = struct.unpack(
            ">I",
            reply_buffer[:4]
        )[0]

        if size > 1024 * 1024:
            raise ConnectionError(
                f"Ungueltige Reply-Groesse: {size}"
            )

        if len(reply_buffer) < 4 + size:
            break

        del reply_buffer[:4 + size]


# ============================================================
# Hyperion Verbindung
# ============================================================

def connect_hyperion():

    while running:

        sock = None

        try:

            print(
                f"Verbinde mit Hyperion "
                f"{HYPERION_HOST}:{HYPERION_PORT} ..."
            )

            sock = socket.create_connection(
                (
                    HYPERION_HOST,
                    HYPERION_PORT
                ),
                timeout=3
            )

            # Wichtig:
            # Socket fuer den laufenden Betrieb
            # nicht mehr blockierend betreiben.

            sock.setblocking(False)

            print(
                "Hyperion FlatBuffer verbunden."
            )

            # Register senden
            register = build_register()

            send_message(
                sock,
                register
            )

            # Kurz Zeit geben, damit Hyperion
            # die Register-Reply erzeugen kann.
            time.sleep(0.01)

            reply_buffer = bytearray()

            try:
                read_reply_nonblocking(
                    sock,
                    reply_buffer
                )
            except BlockingIOError:
                pass

            print(
                f"Hyperion registriert: "
                f"priority={PRIORITY}, "
                f"origin={ORIGIN}"
            )

            return sock, reply_buffer

        except (
            OSError,
            ConnectionError
        ) as e:

            print(
                f"Hyperion nicht erreichbar: {e}"
            )

            if sock is not None:

                try:
                    sock.close()
                except Exception:
                    pass

            if running:
                time.sleep(1)

    return None, None


# ============================================================
# FFmpeg
# ============================================================

def start_ffmpeg():

    cmd = [
        "ffmpeg",

        "-hide_banner",
        "-loglevel", "error",

        "-f", "kmsgrab",
        "-device", "/dev/dri/card1",

        "-framerate", str(FPS),

        "-i", "-",

        "-vf",
        (
            "hwdownload,"
            "format=bgr0,"
            f"scale={WIDTH}:{HEIGHT},"
            "format=rgb24"
        ),

        "-f", "rawvideo",
        "-pix_fmt", "rgb24",

        "pipe:1",
    ]

    print("Starte FFmpeg:")
    print(" ".join(cmd))
    print()

    return subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        bufsize=FRAME_SIZE * 4,
    )


# ============================================================
# Main
# ============================================================

def main():

    global running

    print()
    print(
        "VDR KMSgrab -> Hyperion FlatBuffer"
    )
    print("-----------------------------------")
    print("/dev/dri/card1")
    print(f"{WIDTH}x{HEIGHT}")
    print(f"{FPS} fps")
    print(f"{FRAME_SIZE} Bytes RGB24")
    print(
        f"{HYPERION_HOST}:{HYPERION_PORT}"
    )
    print()

    ffmpeg = start_ffmpeg()

    sock = None
    reply_buffer = bytearray()

    frame_count = 0

    start_time = time.monotonic()
    last_report = start_time

    try:

        while running:

            # ------------------------------------------------
            # Verbindung herstellen
            # ------------------------------------------------

            if sock is None:

                sock, reply_buffer = (
                    connect_hyperion()
                )

                if sock is None:
                    break

            # ------------------------------------------------
            # Hyperion Replies nebenbei abholen
            # ------------------------------------------------

            try:

                read_reply_nonblocking(
                    sock,
                    reply_buffer
                )

            except (
                ConnectionError,
                OSError
            ) as e:

                print(
                    f"Hyperion-Verbindung verloren: {e}"
                )

                try:
                    sock.close()
                except Exception:
                    pass

                sock = None
                continue

            # ------------------------------------------------
            # Einen Frame lesen
            # ------------------------------------------------

            frame = ffmpeg.stdout.read(
                FRAME_SIZE
            )

            if len(frame) != FRAME_SIZE:

                print(
                    f"FFmpeg: erwartet "
                    f"{FRAME_SIZE} Bytes, "
                    f"erhalten {len(frame)}"
                )

                break

            # ------------------------------------------------
            # FlatBuffer bauen
            # ------------------------------------------------

            payload = build_image(frame)

            # ------------------------------------------------
            # Frame senden
            # ------------------------------------------------

            try:

                send_message(
                    sock,
                    payload
                )

                frame_count += 1

            except (
                BrokenPipeError,
                ConnectionResetError,
                ConnectionAbortedError,
                OSError
            ) as e:

                print(
                    f"Hyperion-Verbindung verloren: {e}"
                )

                try:
                    sock.close()
                except Exception:
                    pass

                sock = None

                continue

            # ------------------------------------------------
            # Statistik
            # ------------------------------------------------

            now = time.monotonic()

            if now - last_report >= 5:

                elapsed = (
                    now - start_time
                )

                real_fps = (
                    frame_count / elapsed
                    if elapsed > 0
                    else 0
                )

                print(
                    f"{frame_count} Frames | "
                    f"{real_fps:.1f} fps | "
                    f"{len(payload)} Byte FlatBuffer | "
                    f"Replies im Puffer: "
                    f"{len(reply_buffer)}"
                )

                last_report = now

    finally:

        running = False

        # ----------------------------------------------------
        # Priority freigeben
        # ----------------------------------------------------

        if sock is not None:

            try:

                clear = build_clear()

                send_message(
                    sock,
                    clear
                )

            except Exception:
                pass

            try:
                sock.close()
            except Exception:
                pass

        # ----------------------------------------------------
        # FFmpeg beenden
        # ----------------------------------------------------

        try:

            ffmpeg.terminate()
            ffmpeg.wait(timeout=2)

        except Exception:

            try:
                ffmpeg.kill()
            except Exception:
                pass

        print()
        print("Grabber beendet.")


if __name__ == "__main__":
    main()

Außer hyperion-ng müssen folgende MLD-Pakete installiert sein:
  • ffmpeg
  • python3-pip
dann im Terminal:
Code: [Select]
python3 -m pip install flatbuffers
python3 /usr/share/hyperion/vdr-kmsgrab-flatbuf.py

Antwort etwa:
Code: [Select]
VDR KMSgrab -> Hyperion FlatBuffer
-----------------------------------
/dev/dri/card1
160x90
25 fps
43200 Bytes RGB24
127.0.0.1:19400

Starte FFmpeg:
...

Verbinde mit Hyperion 127.0.0.1:19400 ...
Hyperion FlatBuffer verbunden.
Hyperion registriert: priority=100, origin=VDR-KMSgrab
124 Frames | 24.7 fps | 43272 Byte FlatBuffer | Replies im Puffer: 0
249 Frames | 24.8 fps | 43272 Byte FlatBuffer | Replies im Puffer: 0
...

Die in Hyperion eingestellten LEDs sollten je nach Bildschirminhalt leuchten.

Wenn alles funktioniert am besten einen systemd-Service anlegen, der das Script beim Booten startet:
Code: [Select]
nano /etc/systemd/system/vdr-kmsgrab.service
Inhalt:

Code: [Select]
[Unit]
Description=VDR KMSgrab to Hyperion FlatBuffer
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 -u /usr/share/hyperion/vdr-kmsgrab-flatbuf.py
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

systemd neu laden
Code: [Select]
systemctl daemon-reload
Dienst testweise starten
Code: [Select]
systemctl start vdr-kmsgrab.service
Dann:
Code: [Select]
systemctl status vdr-kmsgrab.service
Ausgabe etwa:
Code: [Select]
Active: active (running)
Live-Log ansehen:
Code: [Select]
journalctl -u vdr-kmsgrab.service -f
Es sollten die bisherigen Meldungen erscheinen:
Code: [Select]
Hyperion FlatBuffer verbunden.
Hyperion registriert: priority=100, origin=VDR-KMSgrab
124 Frames | 24.7 fps | 43272 Byte FlatBuffer
249 Frames | 24.8 fps | 43272 Byte FlatBuffer
...

Wenn das funktioniert und die LEDs leuchten, automatischen Start aktivieren:
Code: [Select]
systemctl enable vdr-kmsgrab.service
Oder direkt aktivieren und starten:
Code: [Select]
systemctl enable --now vdr-kmsgrab.service
Damit läuft das Grabber-Script nach einem Neustart automatisch.

Ich wollte diesen Text eigentlich im Wiki ergänzen, aber die Syntax dort schreckt mich ab!

Schöne Grüße
Uwe
32
Allgemein [ General ] / Install Problem mit 6.5 auf eine Festplatte
« Last post by Doc Schnuggels on September 13, 2026, 21:08:22 »
Hi Claus
Habe auch die Maus abgezogen
Doch alles was ich mache führt nicht zum Erfolg ( Board AAHD2-HY mit AMD A6 3600 CPU mit 2x4 GB RAM ) Nvidia GT710 und Tevi S2 480 Twin Satkarte
Breche die Sache ab
Mit diesem Board von HP hat das keinen Zweck
Sogar wenn kein Systemlüfter angeschlossen ist bootet das Board nicht durch , ohne Worte
Vielen Dank für Deine Mühe Claus , Schade um die Zeit .
Habe ja noch ein anderes MLD 6.5 System
Siehe meine Signatur
MfG Helmut
33
Allgemein [ General ] / Install Problem mit 6.5 auf eine Festplatte
« Last post by clausmuus on September 13, 2026, 20:20:35 »
Das sind nur Kernel Log Meldungen, die ärgerlicherweise auf der Konsole angezeigt werden, nachdem der Prompt bereits aktiv ist.
Sofern nicht ständig weitere Meldungen kommen, kannst Du einfach mal ENTER drücken, um eine leere Eingabe Zeile zu bekommen. Auch wenn immer weiter Log Meldungen kommen, kannst Du einfach blind die befehle eingeben, was aber wirklich keinen Spaß macht :(
Du könntest auch einfach die Maus abziehen, die die Probleme macht.
34
Allgemein [ General ] / Install Problem mit 6.5 auf eine Festplatte
« Last post by Doc Schnuggels on September 13, 2026, 19:39:41 »
Hier im Anhang ein Bild vom Bootvorgang
35
Allgemein [ General ] / Kodi geht nicht
« Last post by clausmuus on September 13, 2026, 19:11:40 »
Du könntest Kodi mal auf der Konsole starten und schauen ob es mehr Logs gibt:
Code: [Select]
/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=kodi tv.kodi.Kodi
36
Allgemein [ General ] / Install Problem mit 6.5 auf eine Festplatte
« Last post by clausmuus on September 13, 2026, 19:04:40 »
Ne, nach der Meldung sollte ein Promt (ein "> " oder "# ") angezeigt werden, also die Möglichkeit die Befehle einzugeben.
Ich bräuchte mal ein kurzes Video (oder wenigstens ein Foto) welches das Booten und vor allem alles ab dem Anzeigen der Meldung Zeigt. Ansonsten reden wir vermutlich an einander vorbei.
37
Allgemein [ General ] / vdr-plugin-graphtft-ng Problem
« Last post by horatio on September 13, 2026, 18:28:36 »
Dieses Mal klappt es auch nach dem Neustart. Ich werde mal die Tage schauen, ob sich was ändert, aber ich glaube dieses Mal haben wir es  :)
Dank Dir recht herzlich.
Im Anhang mal ein staubiges Regal mit Display  ;D 8)
38
Allgemein [ General ] / Kodi geht nicht
« Last post by rkp on September 13, 2026, 17:44:55 »
Bitte das Log zeitlich von unten nach oben lesen!
39
Allgemein [ General ] / Kodi geht nicht
« Last post by rkp on September 13, 2026, 17:37:00 »
Kodi startet immer neu beim Anwählen eines Menüpunktes. Im Log steht dann dort immer:

Code: [Select]
[Sep 13 17:30:48 MLD systemd[1]: Started Foreground app.
Sep 13 17:30:48 MLD systemd[1]: Cannot find unit for notify message of PID 3881, ignoring.
Sep 13 17:30:48 MLD systemd[1]: Starting Foreground app...
Sep 13 17:30:48 MLD systemd[1]: Stopped Foreground app.
Sep 13 17:30:48 MLD systemd[1]: appstarter.service: Deactivated successfully.
Sep 13 17:30:48 MLD systemd[1]: Stopping Foreground app...
Sep 13 17:30:48 MLD vdr[1219]: [1219] executing command 'setting call apps.start '


Kodi wird jedesmal neu gestartet.

40
Allgemein [ General ] / Install Problem mit 6.5 auf eine Festplatte
« Last post by Doc Schnuggels on September 13, 2026, 17:29:48 »
Hallo Claus
Habe das Laufwerk bei mir gefunden .
Es ist nach Eingabe von ls /dev/sd*  Laufwerk sdb1
Nun habe ich versucht nachdem der install USB Stick gestartet ist nach dem Eintrag   can´t find rootfs.img /run/media/* dropping to a shell
Die Eingabe von
mkdir /run/media/sdb1
mount /dev/sdb1 /run/media/sdb1
exit
Einzugeben, doch der Install läuft weiter und sucht alle USB Ports des Motherboards ab
Wie kann ich den den Bootvorgang stoppen und die Eingaben machen zu können. Einfach die Eingaben zu machen funzt nicht , er bleibt nicht stehen.
Zur Zeit ist noch MLD 5.5 auf der Festplatte.
Vllt kann man ja von dort aus den Install Stick auf sdb1 editieren . Doch wie . mc ist auch installiert.
Fazit:  ich hab,s noch nicht hin bekommen.
Noch eine Idee
Gruß Helmut