Hardware accelerated playback with mpv and nv-sglrun

Using mpv with nv-sglrun for hardware accelerated playback

packages

Bash:
doas pkg install libc6-shim mpv

nv-sglrun

Check the supported codecs

Bash:
nv-sglrun env LIBVA_DRIVER_NAME=nvidia-drm vainfo

mpv.conf

create the mpv directory and config file

Bash:
mkdir -p ~/.config/mpv

Bash:
vi ~/.config/mpv/mpv.conf

nvdec-copy section

Use nvdec-copy

Code:
#===============================================================================
# hardware acceleration profile
#===============================================================================

[hwdec]
profile-desc="hardware acceleration, no cache, yt-dlp 1080 or less"
vo=gpu
gpu-context=wayland
hwdec=nvdec-copy

yt-dlp section

yt-dlp format select hardware supported codecs with a fallback

Code:
#===============================================================================
# yt-dlp format
# Prefers HW-supported codecs (H.264/VP9/HEVC/VP8) up to 1080p SDR (8-bit nv12).
# Fallbacks: 1) 10-bit stream, 2) Any 1080p stream (e.g. AV1 SW), 3) Best pre-merged.
#===============================================================================

ytdl-format="bv*[vcodec~='(?i)^(avc1|vp09|vp9|vp8|h264|hevc|h265)'][dynamic_range=SDR][height<=?1080]+ba/bv*[vcodec~='(?i)^(avc1|vp09|vp9|vp8|h264|hevc|h265)'][height<=?1080]+ba/bv*[height<=?1080]+ba/best[height<=?1080]/best"

mpv.conf full config

Code:
#===============================================================================
# mpv mpv.conf
#===============================================================================

# list profiles with: mpv --profile=help

#===============================================================================
# load hwdec profile automatically
#===============================================================================

profile=hwdec


#===============================================================================
# hardware acceleration profile
#===============================================================================

[hwdec]
profile-desc="hardware acceleration, no cache, yt-dlp 1080 or less"
vo=gpu
gpu-context=wayland
hwdec=nvdec-copy
#hwdec=vaapi


#===============================================================================
# msg-level
#===============================================================================

msg-level=ffmpeg=fatal


#===============================================================================
# cache no for internet streams
#===============================================================================

cache=no


#===============================================================================
# yt-dlp format
# Prefers HW-supported codecs (H.264/VP9/HEVC/VP8) up to 1080p SDR (8-bit nv12).
# Fallbacks: 1) 10-bit stream, 2) Any 1080p stream (e.g. AV1 SW), 3) Best pre-merged.
#===============================================================================

ytdl-format="bv*[vcodec~='(?i)^(avc1|vp09|vp9|vp8|h264|hevc|h265)'][dynamic_range=SDR][height<=?1080]+ba/bv*[vcodec~='(?i)^(avc1|vp09|vp9|vp8|h264|hevc|h265)'][height<=?1080]+ba/bv*[height<=?1080]+ba/best[height<=?1080]/best"


#===============================================================================
# show milliseconds in the on screen display
#===============================================================================

osd-fractions


#===============================================================================
# youtube subs - J to switch to subs
#===============================================================================

sub-auto=fuzzy
ytdl-raw-options=sub-lang="en",write-sub=,write-auto-sub=
sub-font='NotoColorEmoji'


#===============================================================================
# screenshot timecode
#===============================================================================

screenshot-template="%F-[%P]v%#01n"


#===============================================================================
# cache profile: mpv --profile=cache
#===============================================================================

[cache]
profile-desc="hardware acceleration, cache, yt-dlp 1080 or less"
# include hwdec profile
profile=hwdec
# override hwdec profile cache setting
cache=auto


#===============================================================================
# youtube conditional auto profile match any youtube url
#===============================================================================

[youtube]
profile-desc="youtube hardware acceleration, cache"
profile-cond=path:find('youtu%.?be') ~= nil
#profile-cond=path:find('youtu%.?be') ~= nil or path:find('googlevideo%.com') ~= nil
# include hwdec profile
profile=hwdec
# override hwdec profile cache setting
cache=yes
# fullscreen 2nd display
fs
fs-screen-name=DP-3


#===============================================================================
# invidious conditional auto profile match any invidious url
#===============================================================================

[invidious]
profile-desc="invidious hardware acceleration, cache"
profile-cond=path:find('http://192.168.1.236:3000') ~= nil
# include hwdec profile
profile=hwdec
# override hwdec profile cache setting
cache=yes
# fullscreen 2nd display
fs
fs-screen-name=DP-3


#===============================================================================
# archive.org conditional auto profile match any archive.org url
#===============================================================================

[archive]
profile-desc="archive hardware acceleration, cache"
profile-cond=path:find('archive.org') ~= nil
# include hwdec profile
profile=hwdec
# override hwdec profile cache setting
cache=auto
# fullscreen 2nd display
fs
fs-screen-name=DP-3


#===============================================================================
# bbc iplayer conditional auto profile match any bbc iplayer url
#===============================================================================

[iplayer]
profile-desc="iplayer hardware acceleration, cache"
profile-cond=path:find('bbc.co.uk/iplayer') ~= nil
# include hwdec profile
profile=hwdec
# override hwdec profile cache setting
cache=yes
# fullscreen 2nd display
fs
fs-screen-name=DP-3


#===============================================================================
# bbc iplayer conditional auto profile match any bbc iplayer url
#===============================================================================

[bbc]
profile-desc="bbc hardware acceleration, cache"
profile-cond=path:find('bbc:pips:service') ~= nil
# include hwdec profile
profile=hwdec
# override hwdec profile cache setting
cache=yes
# fullscreen 2nd display
fs
fs-screen-name=DP-3

create the bin directory

Bash:
mkdir -p ~/bin

zshenv

Set you shell path to include the ~/bin directory first in the path

Code:
#===============================================================================
# Path
#===============================================================================

typeset -U PATH path
path=("$HOME/bin" "$HOME/.local/bin" "/usr/local/bin" "$path[@]")
export PATH

mpv script

Copy the mpv script to ~/bin

Bash:
cp mpv ~/bin

Make it executable

Bash:
chmod +x ~/bin/mpv

mpv script

Bash:
#!/bin/sh

#===============================================================================
# mpv wrapper script to use nv-sglrun and nvdec-copy
#===============================================================================

#===============================================================================
# ~/.config/mpv/mpv.conf
# vo=gpu
# gpu-context=wayland
# hwdec=nvdec-copy
#===============================================================================

#===============================================================================
# exit if no arguments passed to script
#===============================================================================

[ $# -gt 0 ] || exit 0

#===============================================================================
# run the wrapper-freebsd script
#===============================================================================

nv-sglrun /usr/local/bin/mpv "${@}"

Run rehash to pick up the mpv script

Bash:
rehash

Run which mpv

Bash:
which mpv

That will show that the mpv script is being used
instead of the default mpv binary

Code:
/home/djwilcox/bin/mpv

Playing a local 4k video

Code:
[i] Yes Master ? mpv upscale/terracevideonocc-4k.mp4
/usr/local/lib/libc6-shim/libc6.so: shim init
● Video  --vid=1  (hevc 3840x2160 24 fps) [default]
● Audio  --aid=1  (aac 2ch 48000 Hz 128 kbps) [default]
Using hardware decoding (nvdec-copy).
AO: [oss] 48000Hz stereo 2ch float
VO: [gpu] 3840x2160 nv12

Notice Using hardware decoding (nvdec-copy)
and VO: [gpu] 3840x2160 nv12
 
There are three useful "gpu top" type monitor programs that are useful to check gpu video acceleration and perform troubleshooting. You can use these to check how well video acceleration is working on your particular gpu.

for intel gpu: intel_gpu_top
for AMD: radeontop
for nvidia: nvidia-smi

If you search online you can find various howtos and guides that describe how to use them. For example, a useful page about the intel one is here https://deepwiki.com/rib/intel-gpu-tools/5.2.1-intel_gpu_top
 
For nvidia-smi you have to prefix it with nv-sglrun
to show the cuda version

nvidia-smi

Code:
[i] Yes Master ? nvidia-smi
Tue Jul 28 19:26:08 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 595.84                 Driver Version: 595.84         CUDA Version: N/A      |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce GTX 1650        Off |   00000000:01:00.0 Off |                  N/A |
| N/A   65C    P0             13W /   50W |      83MiB /   4096MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A           94880      C   /usr/local/bin/mpv                       81MiB |
+-----------------------------------------------------------------------------------------+

nv-sglrun nvidia-smi

Code:
[i] Yes Master ? nv-sglrun nvidia-smi
/usr/local/lib/libc6-shim/libc6.so: shim init
Tue Jul 28 19:27:28 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 595.84                 Driver Version: 595.84         CUDA Version: 13.2     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA GeForce GTX 1650        Off |   00000000:01:00.0 Off |                  N/A |
| N/A   65C    P0             13W /   50W |      83MiB /   4096MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI              PID   Type   Process name                        GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+

You can also use the loop option to update the output

Code:
-l SEC, --loop=SEC
Probe until Ctrl+C at specified second interval.

Loop 1 second to update the output every second

Code:
nv-sglrun nvidia-smi -l 1
 
Back
Top