From db018af77cf0130dead134bb4b5bd6fae89867d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 25 Jun 2026 07:36:55 +0000 Subject: [PATCH 1/2] Fix VAAPI hardware decode on LibreELEC x86_64 by building from source The upstream moonlight-qt AppImage was compiled without SDL_VIDEO_DRIVER_KMSDRM, causing vaapi.cpp's KMSDRM display path to be excluded at compile time. On LibreELEC (headless KMS), SDL reports subsystem SDL_SYSWM_KMSDRM (13), which fell through to "Unsupported VAAPI rendering subsystem" and forced software decode. Fix: build moonlight-qt from source using Debian bookworm's libsdl2-dev, which has SDL_VIDEO_DRIVER_KMSDRM defined in its headers. Also add runtime libs: - libSDL2.so* (previously came from AppImage, now must be bundled explicitly) - libGLESv2.so* (rendering stability on GLES2/EGLFS path) - libdrm.so* (required by the VAAPI DRM display path at runtime) Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01JCvMzW9nTj4VvqGiyFdt8T --- resources/build/libreelec/Dockerfile.amd64 | 57 ++++++++++++++----- .../create_standalone_moonlight_qt.sh | 4 ++ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/resources/build/libreelec/Dockerfile.amd64 b/resources/build/libreelec/Dockerfile.amd64 index 224d1a2..0833b8d 100644 --- a/resources/build/libreelec/Dockerfile.amd64 +++ b/resources/build/libreelec/Dockerfile.amd64 @@ -2,21 +2,49 @@ ARG DEBIAN_RELEASE=bookworm FROM debian:${DEBIAN_RELEASE}-slim -# Install required packages and download Moonligh-qt AppImage version +# Install build dependencies and runtime libraries. +# We build moonlight-qt from source rather than extracting the upstream AppImage +# so that it is compiled against Debian's libsdl2-dev, which has SDL_VIDEO_DRIVER_KMSDRM +# defined. The upstream AppImage was built without this flag, which caused +# vaapi.cpp's KMSDRM display path to be compiled out, preventing hardware-accelerated +# video decoding on KMS/DRM displays (e.g. LibreELEC on generic x86_64). RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y \ + build-essential \ + git \ + pkg-config \ + qt5-qmake \ + qtbase5-dev \ + qtbase5-private-dev \ + qtdeclarative5-dev \ + libqt5svg5-dev \ + libqt5quickcontrols2-5 \ + qml-module-qtquick-controls2 \ + qml-module-qtquick-layouts \ + qml-module-qtquick-window2 \ + qml-module-qtquick2 \ + libsdl2-dev \ + libva-dev \ + libdrm-dev \ + libavcodec-dev \ + libavutil-dev \ + libswscale-dev \ + libswresample-dev \ + libopus-dev \ + libssl-dev \ + libcurl4-openssl-dev \ libatomic1 \ libfuse2 \ libgl1 \ libgl1-mesa-dri \ + libgles2 \ + libglib2.0-dev \ libgudev-1.0-0 \ libinput10 \ libqt5core5a \ libqt5gui5 \ libqt5network5 \ libqt5qml5 \ - libqt5quickcontrols2-5 \ - libqt5svg5 \ libsm6 \ libva-wayland2 \ libvdpau-va-gl1 \ @@ -24,20 +52,23 @@ RUN apt-get update \ libxcb-cursor0 \ libxcursor1 \ libxi6 \ - qml-module-qtquick-controls2 \ - qml-module-qtquick-layouts \ - qml-module-qtquick-window2 \ - qml-module-qtquick2 \ - wget \ && apt-get clean \ - && rm -rf /var/lib/apt/lists/* \ - && DOWNLOAD_URL=$(wget --quiet --header "Accept: application/vnd.github.v3+json" --output-document - https://api.github.com/repos/moonlight-stream/moonlight-qt/releases/latest | grep -o '"browser_download_url": "[^"]*' | grep -o '[^"]*$' | grep ".AppImage") \ - && wget "${DOWNLOAD_URL}" -O /tmp/Moonlight-downloaded.AppImage \ - && chmod a+x /tmp/Moonlight-downloaded.AppImage + && rm -rf /var/lib/apt/lists/* +# Clone and build moonlight-qt from source. +# MOONLIGHT_VERSION can be overridden at build time, e.g. --build-arg MOONLIGHT_VERSION=v6.1.0 +ARG MOONLIGHT_VERSION=master +RUN git clone --depth 1 --branch ${MOONLIGHT_VERSION} \ + https://github.com/moonlight-stream/moonlight-qt.git /tmp/moonlight-qt-src \ + && cd /tmp/moonlight-qt-src \ + && git submodule update --init --recursive \ + && qmake moonlight-qt.pro \ + && make -j$(nproc) \ + && install -m 755 app/moonlight /usr/bin/moonlight-qt \ + && rm -rf /tmp/moonlight-qt-src # Script to extract the needed libraries COPY create_standalone_moonlight_qt.sh /tmp/ RUN chmod a+x /tmp/create_standalone_moonlight_qt.sh -ENTRYPOINT [ "/tmp/create_standalone_moonlight_qt.sh" ] \ No newline at end of file +ENTRYPOINT [ "/tmp/create_standalone_moonlight_qt.sh" ] diff --git a/resources/build/libreelec/create_standalone_moonlight_qt.sh b/resources/build/libreelec/create_standalone_moonlight_qt.sh index 6970b30..e10c39d 100644 --- a/resources/build/libreelec/create_standalone_moonlight_qt.sh +++ b/resources/build/libreelec/create_standalone_moonlight_qt.sh @@ -23,6 +23,7 @@ fi USR_DEPENDENCIES=" libEGL.so* libGL.so* + libGLESv2.so* libGLX.so* libGLdispatch.so* libICE.so* @@ -30,6 +31,8 @@ USR_DEPENDENCIES=" libOpenGL.so* libQt5* libQt6* + libSDL2.so* + libSDL2-*.so* libSM.so* libSvtAv1Enc.so* libX11-xcb.so* @@ -55,6 +58,7 @@ USR_DEPENDENCIES=" libcrypto.so* libdatrie.so* libdav1d.so* + libdrm.so* libdouble-conversion.so* libffi.so* libfribidi.so* From 6ee0d2e788c4d81cf227456e8910a63ad2946f23 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 25 Jun 2026 08:01:17 +0000 Subject: [PATCH 2/2] Add GHCR build pipeline and pin versions for reproducible builds - Add GitHub Action to build and push the amd64 Docker image to GHCR on every push to main, with GitHub Actions cache to speed up rebuilds - build.sh now pulls the pre-built image from GHCR instead of compiling locally; falls back to a local build if the pull fails - Pin Dockerfile base image to a specific Debian bookworm-slim digest - Pin MOONLIGHT_VERSION to v6.1.0 (was master) - MOONLIGHT_VERSION is also set as a repo variable so it can be bumped without editing the Dockerfile Co-Authored-By: Claude --- .github/workflows/docker-build.yml | 57 ++++++++++++++++++++++ resources/build/libreelec/Dockerfile.amd64 | 4 +- resources/build/libreelec/build.sh | 16 ++++-- 3 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/docker-build.yml diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 0000000..c1cf5c3 --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,57 @@ +name: Build and push Docker image + +on: + push: + branches: + - main + paths: + - 'resources/build/libreelec/Dockerfile.amd64' + - 'resources/build/libreelec/create_standalone_moonlight_qt.sh' + - '.github/workflows/docker-build.yml' + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=raw,value=${{ vars.MOONLIGHT_VERSION }} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: resources/build/libreelec + file: resources/build/libreelec/Dockerfile.amd64 + push: true + tags: ${{ steps.meta.outputs.tags }} + build-args: | + MOONLIGHT_VERSION=${{ vars.MOONLIGHT_VERSION }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/resources/build/libreelec/Dockerfile.amd64 b/resources/build/libreelec/Dockerfile.amd64 index 0833b8d..8be7e3a 100644 --- a/resources/build/libreelec/Dockerfile.amd64 +++ b/resources/build/libreelec/Dockerfile.amd64 @@ -1,6 +1,6 @@ # Use latest compatible Debian version ARG DEBIAN_RELEASE=bookworm -FROM debian:${DEBIAN_RELEASE}-slim +FROM debian:${DEBIAN_RELEASE}-slim@sha256:1def178129dfb5f24db43afbf2fcac04530012e3264ba4ff81c71184e17a9ee4 # Install build dependencies and runtime libraries. # We build moonlight-qt from source rather than extracting the upstream AppImage @@ -57,7 +57,7 @@ RUN apt-get update \ # Clone and build moonlight-qt from source. # MOONLIGHT_VERSION can be overridden at build time, e.g. --build-arg MOONLIGHT_VERSION=v6.1.0 -ARG MOONLIGHT_VERSION=master +ARG MOONLIGHT_VERSION=v6.1.0 RUN git clone --depth 1 --branch ${MOONLIGHT_VERSION} \ https://github.com/moonlight-stream/moonlight-qt.git /tmp/moonlight-qt-src \ && cd /tmp/moonlight-qt-src \ diff --git a/resources/build/libreelec/build.sh b/resources/build/libreelec/build.sh index 703dbb8..32dbdc4 100755 --- a/resources/build/libreelec/build.sh +++ b/resources/build/libreelec/build.sh @@ -34,16 +34,24 @@ if [ "${PLATFORM_DISTRO_RELEASE%%.*}" -le 10 ]; then BUILD_ARG="--build-arg DEBIAN_RELEASE=bullseye" fi -# Clean up +GHCR_IMAGE="ghcr.io/echocabinet/plugin.program.moonlight-qt:latest" + +# Clean up any previous container/image docker rm --force moonlight-qt &> /dev/null || true docker rmi --force moonlight-qt &> /dev/null || true -# Build -docker build --file "./Dockerfile.${BUILD_FLAVOR}" --compress --tag moonlight-qt --platform "linux/${BUILD_ARCH}" $BUILD_ARG . +# Try pulling the pre-built image from GHCR — much faster than building locally. +# Falls back to a local build if the pull fails (offline, image not yet published, etc). +if docker pull --platform "linux/${BUILD_ARCH}" "$GHCR_IMAGE" 2>/dev/null; then + echo "Using pre-built image from GHCR." + docker tag "$GHCR_IMAGE" moonlight-qt +else + echo "GHCR pull failed or unavailable — building locally (this will take a while)..." + docker build --file "./Dockerfile.${BUILD_FLAVOR}" --compress --tag moonlight-qt --platform "linux/${BUILD_ARCH}" $BUILD_ARG . +fi # Run and get files mkdir -p "$LOCAL_PATH" -docker create --name moonlight-qt moonlight-qt docker run --volume "$LOCAL_PATH":/tmp/moonlight-qt moonlight-qt # Clean up