medias 0.3.9

TV media player on bare DRM/KMS: Vulkan UI plane over libmpv video, for local files, UPnP/DLNA servers and YouTube, controlled by HDMI-CEC remote, evdev or terminal
medias-0.3.9 is not a library.

medias

A TV media player that runs directly on DRM/KMS, without X11 or Wayland. libmpv decodes video into one KMS plane. A Vulkan-rendered UI sits on a second plane, and both are composited in one atomic page flip. Input comes from an HDMI-CEC remote, evdev keyboards and remotes, or the terminal. Targets are the Raspberry Pi and desktop GPUs (e.g. AMD RX 6800); see Hardware.

Features

  • Local library: video and music folders with thumbnails (a frame at 15%, embedded or folder cover art). Per-file resume; search-as-you-type filter with an on-screen keyboard.
  • UPnP/DLNA: discovers media servers via SSDP (e.g. Fritz!Box, minidlna) and browses their ContentDirectory. Album art is shown; items play from their HTTP resources.
  • Folder playback: at the end of a file the next one in its folder plays (on by default, togglable). Next/Previous-track keys skip.
  • YouTube: search, trending, subscriptions, playlists, liked videos (via YouTube Data API v3 sign-in), and "Like your watched" (videos related to watched ones). Streams play directly from InnerTube, with yt-dlp as fallback. The original audio track plays first; dubs in your languages are offered as named tracks.
  • Views: text list, thumbnail list, or a wide thumbnail grid (Yellow/Info toggles).
  • Black screen: Yellow/Info during playback cycles info shown → hidden → black screen. Audio keeps playing, which suits music on OLED TVs.

Requirements

  • Linux with a KMS driver and an EGL/GLES driver (video).
  • Optional: a Vulkan driver with dmabuf import (e.g. Mesa RADV or V3DV, or NVIDIA) for the UI. Without one (e.g. Mali Midgard on RK3399) a CPU rasterizer draws the UI; MEDIAS_UI=cpu forces it.
  • libmpv (package mpv or libmpv-dev). libgbm, libEGL and the Vulkan loader are loaded or linked from the system.
  • Access to /dev/dri/card*, /dev/dri/renderD*, /dev/input/event*, and to /dev/cec* for HDMI-CEC (groups video, render, input).
  • No desktop or display manager holding the display (DRM master); otherwise startup fails with acquire DRM master ... Permission denied. sudo fuser -v /dev/dri/card* shows the holder. Stop it with sudo systemctl stop display-manager, or boot to a console with sudo systemctl set-default multi-user.target.
  • Optional: yt-dlp for the playback fallback and anonymous YouTube search.

Hardware

Video always renders through mpv's OpenGL path; GPU fill rate limits playback more than decoding does. Measurements: PERFORMANCE.md.

Status Hardware Notes
Tested Raspberry Pi 5 Vulkan UI (V3DV). HEVC hwdec; H.264 1080p25 software.
Tested Desktop: AMD (RADV), NVIDIA Vulkan UI.
Expected Raspberry Pi 4 Vulkan UI (V3DV); H.264 and HEVC hwdec. Untested.
Expected RK3588/RK3588S (e.g. Radxa Rock 5C) Mali-G610: PanVK Vulkan, Panthor kernel driver (recent mainline). 4x A76 decode 1080p in software. Untested. Not RK3582 (Rock 5C Lite): its GPU is disabled.
Best effort Allwinner H618 (Orange Pi Zero3) Mali-G31, no Vulkan: CPU UI. 1080p24 H.264 needs profile=fast (MEDIAS_MPV_CONF); 30 ms of a 41.7 ms frame. Set MEDIAS_AUDIO_DEVICE (e.g. alsa/plughw:CARD=HDMI,DEV=0).
Best effort RK3399 (e.g. Asus Tinker Edge R) Mali-T860, no Vulkan: CPU UI. Too slow on vendor kernels; mainline untested.

For a new 1080p box, buy a Raspberry Pi 4 or 5, or an RK3588 board.

Install

cargo install medias
# with the "For you" feed (YouTube's TV OAuth client, see below):
cargo install medias --features youtube-tv

Run

medias                                   # ~/medias/Videos and ~/medias/Music
medias --videos=Movies=/mnt/movies --videos=Series=/mnt/series --music=/mnt/music
medias metadata movie.mkv                # codecs, resolution, fps, bit depth, channels, bitrates
medias --help                            # all options, keys and environment variables

The same command works from a Linux console, SSH or a terminal multiplexer. scripts/medias-vt optionally starts it on a separate VT (see scripts/README.md).

Files under ~/medias

Path Purpose
Videos/, Music/ default library roots
upnp.txt UPnP server description URLs outside multicast reach, one per line
youtube.txt YouTube sources, Label | query per line (yt-dlp query or URL)
youtube_oauth.json Data API sign-in: {"client_id", "client_secret", "api_key"?}
.history resume positions and last-played dates
.youtube_auth, .youtube_tv_auth stored sign-in sessions (mode 0600)
.view, .autoplay list/grid view (default grid); play-next-in-folder on/off
.cache/thumbs/ thumbnail cache

YouTube sign-in

  • Data API (subscriptions, playlists, liked videos): create a Google Cloud OAuth client of type "TVs and Limited Input devices", enable YouTube Data API v3, and put its ID and secret in ~/medias/youtube_oauth.json. "Sign in" then shows a code and a QR code. In the consent screen's "Testing" state, Google expires the refresh token after 7 days.
  • For you (build feature youtube-tv): a second sign-in with YouTube's own TV client (as the Kodi YouTube plugin does). No configuration is needed. The feed loads up to 36 videos. The same sign-in adds "Watched" and "Playlists" (own and saved, up to 200 entries each). MEDIAS_YT_SYNC=1 adds videos played in medias to that account's YouTube watch history (off by default).
  • Without either, search uses yt-dlp anonymously.

Remote keys (summary)

Key Browse Playback
Up/Down move volume
Left/Right page (grid: move) seek ±10 s
OK open / play playback menu
Back up a level back to the library (paused)
Rewind/Fast-forward, Channel ± page seek ±60 s
Forward/Backward (Next/Previous track) page next/previous file in folder
Red / Green — subtitles / audio track
Blue on-screen keyboard playback menu
Yellow list/grid view info → hidden → black screen

License

GPL-2.0-or-later (LICENSE). The embedded Liberation Sans font is under the SIL Open Font License 1.1 (assets/LiberationSans-OFL.txt).