UPDATED: Fixed Screen Tearing in MPV on Raspberry Pi 4b using Docker

The version of mpv shipped with the current Raspbian release,

<pi@pi1:~>
$ mpv --version
mpv 0.29.1 Copyright © 2000-2018 mpv/MPlayer/mplayer2 projects
 built on UNKNOWN
ffmpeg library versions:
   libavutil       56.14.100 (runtime 56.22.100)
   libavcodec      58.18.100 (runtime 58.35.100)
   libavformat     58.12.100 (runtime 58.20.100)
   libswscale      5.1.100 (runtime 5.3.100)
   libavfilter     7.16.100 (runtime 7.40.101)
   libswresample   3.1.100 (runtime 3.3.100)
ffmpeg version: 4.1.6-1~deb10u1+rpt1

was giving me a bunch of screen tearing. I wanted to just include the upstream Debian apt repos and use apt preferences to select what packages to use. That didnt work out, and I read on the rpi forums that there was some incompatibility between the two distros.

Docker to the rescue.

Kinda. I had to make a bunch of concessions on best practices in order to get it to work. The largest glaring issue being having to run the mpv process inside the Debian container with root perms. If you find a fix to that, let me know. I don’t keep sensitive info on the pi, so, deal with it. Here is my dockerfile and commands for running it. I will strip out some of the stuff specific to my use case. It is a nice multistage Dockerfile. To get sound working with pulse audio, I also included the pulse-client.conf. There may be too many packages added, the line with va-driver on it may not be necessary.

I got it working so I stopped working on it.

FROM arm32v7/debian:bullseye as base

ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get -y update && \
    apt-get -y dist-upgrade && \
    apt-get -y --no-install-recommends install \
        sudo

FROM base as build

RUN apt-get -y --no-install-recommends install \
        python3-dev \
        python3-pip \
    && \
    python3 -m pip install youtube-dl

FROM arm32v7/debian:bullseye as release

RUN apt-get -y --no-install-recommends install \
        ca-certificates \
        ffmpeg \
        lua-socket luarocks \
        mpv \
        va-driver vdpau-driver-all vainfo \
        libgles2-mesa

RUN rm -rf /var/lib/apt

COPY --from=build /usr/local /usr/local
COPY pulse-client.conf /etc/pulse/client.conf
COPY config /home/

ENTRYPOINT /usr/bin/mpv

pulse-client.conf

# Connect to the host's server using the mounted UNIX socket
default-server = unix:/run/user/1000/pulse/native
#default-server = unix:/tmp/pulse-socket

# Prevent a server running in the container
autospawn = no
daemon-binary = /bin/true

# Prevent the use of shared memory
enable-shm = false

Here is how I run it

#!/bin/bash

WORKDIR=$(dirname $(realpath $0))
cd $WORKDIR

uid=1000
APPUSER=pi

TAG=ds1:6000/justinhop/mpv:works

# These fix fullscreen and socket ownership, known hack. Welcome to the Pi
{ sleep 5s; xdotool key f f ; } &
{ sleep 10s; sudo chown pi:pi /run/user/1000/mpv.socket ; } &

exec docker run -it --rm --user 0:0 -e HOME=/home/pi \
    --name=mpv \
    -e TZ \
    -e DISPLAY \
    -v "$WORKDIR/config:/home/${APPUSER}/.config" \
    -v "$WORKDIR/cache:/home/${APPUSER}/.cache" \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    ${TAG} $*

Arguments to docker run that may help you. I went back and forth with using them

    -e DBUS_SESSION_BUS_ADDRESS \
    -e XDG_RUNTIME_DIR \
    -e XDG_CONFIG_HOME=/home/$APPUSER/.config \
    --privileged \
    --security-opt="seccomp=unconfined" \
    --security-opt="apparmor=unconfined" \
    -v /run/user/$uid:/run/user/$uid \
    -v /run/dbus:/run/dbus \
    -v /var/run/dbus:/var/run/dbus \

2021-01-20 Update. New dockerfile. Much smaller. Same permission issues.

FROM --platform=linux/arm/v7 alpine:latest
LABEL maintainer="Justin Hoppensteadt <justinrocksmadscience+git@gmail.com>"


RUN apk add --no-cache \
        ca-certificates \
        bash \
        mpv \
        mesa-dri-gallium \
        py3-pip \
    && \
    python3 -m pip install --upgrade youtube-dl


COPY pulse-client.conf /etc/pulse/client.conf

ENTRYPOINT /usr/bin/mpv

Alpine Linux rocks

Docker Commands

I’m going to put tiny Docker tips here.

Here is the first one. Use docker images to get the information you actually want. Reverse sorted by size so you can clean it up.

docker images | sort --human-numeric-sort -k 7

Here is some truncated sample output

<juser1@laptop1:~>(home laptop)
zsh/2 69315 % docker images | sort --human-numeric-sort -k 7
REPOSITORY                                                  TAG                  IMAGE ID       CREATED         SIZE
busybox                                                     latest               e02e811dd08f   4 years ago     1.09MB
quay.io/prometheus/busybox                                  latest               747e1d7f6665   3 years ago     2.59MB
alpine                                                      3.6                  76da55c8019d   3 years ago     3.97MB
alpine                                                      3.5                  4a415e366388   3 years ago     3.99MB
alpine                                                      3.7                  e21c333399e0   3 years ago     4.14MB
alpine                                                      edge                 5c4fa780951b   2 years ago     4.15MB
alpine                                                      <none>               3fd9065eaf02   2 years ago     4.15MB
alpine                                                      3.8                  11cd0b38bc3c   2 years ago     4.41MB
byrnedo/alpine-curl                                         latest               549652d9246e   3 years ago     5.35MB
...
<none>                                                      <none>               8027707d7b33   18 hours ago    840MB
justinhop/brave                                             2020-12-06           b89c27bfdb18   3 weeks ago     846MB
justinhop/brave                                             latest               b89c27bfdb18   3 weeks ago     846MB
justinhop/synfig                                            2020-12-07           b3f261d67bcb   3 weeks ago     846MB
justinhop/synfig                                            latest               b3f261d67bcb   3 weeks ago     846MB

Clean up unnamed and hanging docker processes and images. You should really use the --rm flag to docker run

docker ps -a |grep Exited | awk '{ print $1 }' | xargs -r docker rm

docker rmi $(docker images -q -f dangling=true)

I run the commands above through cron daily, to keep my file systems from filling up.