2026年9月12日土曜日

DGX Spark をデジタルフォトフレーム化する

DGX Spark(GX10)にデジタルフォトフレーム機能を追加する作業を記録をまとめた。

結果だけ見たい方は mikoto2000/dgx-spark-photoframe: GUI 無しの DGX Spark をデジタルフォトフレーム化するモノ を参照。

目標

まず目標の確認から。

  1. 15 秒ごとに photo ディレクトリ以下の画像をディスプレイに表示したい
  2. 表示はフルスクリーンで
  3. X, Wayland は使いたくない
  4. 電源 ON にしたら自動でフォトフレーム機能を実行してほしい

現状確認

次は現状確認。

現状はこのブログの手順を実行した直後という感じ。

  • https://mikoto2000.blogspot.com/2026/09/dgx-sparkasus-ascent-gx10.html
  • https://mikoto2000.blogspot.com/2026/09/dgx-sparkasus-ascent-gx102-deepseek-v4.html

USB-C モニタが認識されない問題に遭遇

USB-C のモニタを接続したが、認識してくれない。原因を調査していく。

この不具合に当たっている。

対応策は sudo apt purge nvidia-drm-options-modeset0 らしい。試してみる。

モニタの回路から完全に電源を抜かなければならない。

sudo apt purge nvidia-drm-options-modeset0 してから poweroff して、GX10 の電源ケーブルを抜いて 1 分程度待ってから電源をつける。

無事モニタが認識され、ログインプロンプトが表示された。

フォトフレーム機能の実装

なんかファイルを作ってばかりで進捗をツイートしにくい。

デジタルフォトフレーム機能のための Dockerfile と compose.yaml を作っている。

Dockerfile

まず Dockerfile はこれ。シンプルに mpv だけインストールした Ubuntu 環境。

FROM ubuntu:24.04

ENV DEBIAN_FRONTEND=noninteractive

RUN apt-get update \
    && apt-get install -y --no-install-recommends \
       mpv \
    && rm -rf /var/lib/apt/lists/*

COPY entrypoint.sh /entrypoint.sh

RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

次は entrypoint.sh。指定された写真フォルダ内の画像を再帰的に探して mpv に渡す。

#!/bin/bash

# コマンド実行時にエラーが発生したら即終了する。
# 未定義変数の参照や、パイプ途中のコマンド失敗もエラーとして扱う。
set -euo pipefail

# /photos 配下から表示対象の画像ファイルを検索し、
# mpv 用のプレイリストを生成する。
#
# 対象形式:
# - JPEG
# - PNG
# - WebP
#
# ファイル名に空白などが含まれていても扱えるよう、
# find では NULL 区切りで取得している。
find /photos \
  -type f \
  \( \
    -iname '*.jpg' -o \
    -iname '*.jpeg' -o \
    -iname '*.png' -o \
    -iname '*.webp' \
  \) \
  -print0 \
  | sort -z \
  | tr '\0' '\n' \
  > /tmp/photos.m3u

# 表示対象の画像が1枚も存在しない場合は、
# mpv を起動せずエラー終了する。
if [ ! -s /tmp/photos.m3u ]; then
  echo "表示可能な画像が /photos に存在しません。" >&2
  exit 1
fi

# mpv を起動し、DRM/KMS を利用して
# デスクトップ環境を介さずモニタへ直接描画する。
#
# DRM_CONNECTOR:
#   使用する DRM connector。
#   例: DP-1
#   未指定の場合は DP-1。
#
# PHOTO_DURATION:
#   1枚の写真を表示する秒数。
#   未指定の場合は15秒。
#
# PHOTO_ROTATE:
#   写真を回転して表示する角度。
#   0 / 90 / 180 / 270 を想定。
#   未指定の場合は0度。
#
# --loop-playlist=inf:
#   最後の写真まで表示したら先頭へ戻り、
#   スライドショーを無限に繰り返す。
#
# exec を使用することで mpv 自体をコンテナの PID 1 とし、
# docker stop などのシグナルを直接受信できるようにする。
exec mpv \
  --vo=drm \
  --drm-device="${DRM_DEVICE:-/dev/dri/card1}" \
  --drm-connector="${DRM_CONNECTOR:-DP-1}" \
  --drm-mode=preferred \
  --video-rotate="${PHOTO_ROTATE:-0}" \
  --profile=sw-fast \
  --fullscreen \
  --no-audio \
  --image-display-duration="${PHOTO_DURATION:-15}" \
  --loop-playlist=inf \
  --playlist=/tmp/photos.m3u

compose.yaml

次は compose.yaml。.env を読み込んでさっきの Dockerfile のイメージを起動する。

services:
  photoframe:
    build:
      context: .

    container_name: dgx-spark-digital-photoframe

    restart: unless-stopped

    devices:
      - "${DRM_DEVICE:-/dev/dri/card1}:${DRM_DEVICE:-/dev/dri/card1}"

    volumes:
      - "${PHOTO_DIR:-./photos}:/photos:ro"

    environment:
      DRM_DEVICE: "${DRM_DEVICE:-/dev/dri/card1}"
      DRM_CONNECTOR: "${DRM_CONNECTOR:-DP-1}"
      PHOTO_DURATION: "${PHOTO_DURATION:-15}"
      PHOTO_ROTATE: "${PHOTO_ROTATE:-0}"

.env(.env.example)

最後に .env(.env.example)。

写真ディレクトリ、出力デバイス、表示秒数、回転角度を指定できる。

# ホスト側の写真ディレクトリ。
# コンテナ内では /photos として読み取り専用でマウントされる。
PHOTO_DIR=~/photos

# 使用する DRM デバイス。
#
# 利用可能な DRM デバイスは、ホスト側で次のコマンドを実行して確認できる。
#
#   ls -l /dev/dri/
#
# 例:
#   card1
#   renderD128
#
# この場合は /dev/dri/card1 を指定する。
DRM_DEVICE=/dev/dri/card1

# 使用する DRM connector。
#
# 接続中の connector は、ホスト側で次のコマンドを実行して確認できる。
#
#   grep -H connected /sys/class/drm/card*-*/status
#
# 例:
#   /sys/class/drm/card0-DP-1/status: connected
#   /sys/class/drm/card0-DP-2/status: disconnected
#
# この場合は DP-1 を指定する。
DRM_CONNECTOR=Unknown-4

# 1枚の写真を表示する時間(秒)。
PHOTO_DURATION=15

# 写真の回転角度。
# 0 / 90 / 180 / 270 を指定する。
# モニタを縦置きする場合は 90 または 270 を指定する。
PHOTO_ROTATE=0

起動

これで .env を書いて docker compose up -d すればモニタに画像が映る。

参考資料

0 件のコメント:

コメントを投稿