Play videos over a tmux pane in the TTY

Introduction

Tiling window managers are great. However, they require a display server and I recently uninstalled mine. I want to emulate a lot of their functionality in the TTY. One thing I liked to do was watching a video in one window while working in some other terminals that are open at the same time.

The first obvious step to do multiple things at once in the TTY is to use a multiplexer. I use tmux for this. You may think that it's not possible to play videos in text mode at all, but luckily the linux kernel gives us the framebuffer device located at /dev/fbX. This framebuffer still allows us to view graphical output.

So the second step is finding a video player that can output to the framebuffer. I use mplayer because it lets you specify a lot of geometry, which is exactly what we need to achieve a tiling window manager-like effect.

Solution

Here is what I came up with:

#!/bin/zsh

clear

font_width=8
font_height=16

pane_cols=$(tput cols)
pane_rows=$(tput lines)

pane_width=$(($pane_cols*$font_width))
pane_height=$(($pane_rows*$font_height))

pane_top=$(tmux list-panes -F "#{pane_top}" -f "#{pane_active}")
pane_left=$(tmux list-panes -F "#{pane_left}" -f "#{pane_active}")

pane_y=$(($pane_top*$font_height))
pane_x=$(($pane_left*$font_width))

image_width=$(exiftool -b -ImageWidth $1)
image_height=$(exiftool -b -ImageHeight $1)

pane_ratio=$(bc -l <<< "$pane_width / $pane_height")
image_ratio=$(bc -l <<< "$image_width / $image_height")

if [[ $image_ratio -gt $pane_ratio ]]; then
        width=$pane_width
        height=$(bc <<< "$width/$image_ratio")
        height_diff=$(($pane_height-$height))
        x=$pane_x
        y=$(($pane_y+$(($height_diff/2))))
else
        height=$pane_height
        width=$(echo "$height*$image_ratio" | bc -l | sed 's/\..*$//')
        width_diff=$(($pane_width-$width))
        y=$pane_y
        x=$(($pane_x+$(($width_diff/2))))
fi

mplayer -vo fbdev2 -zoom -x $width -y $height $1 \
        -geometry $x:$y > /dev/null 2>&1
			

I basically first get the geometry of my tmux panes in pixels and then geometry of my video in pixels using exiftool. Then I calculate the aspect ratios of both the video and the pane. If the width:height aspect ratio is higher in the video than in the pane this means the video is more horizontal and therefor it is fit to the width of the pane. If the ratio is smaller in the video than in the pane it is fit to the height. I also give mplayer some coordinates on where to put the top left corner of the video so that it is always placed nicely in the center of the pane.

To run this script you need to have zsh, exiftool, bc and of course mplayer and tmux installed.

Shortcomings

When resizing the tmux pane mplayer is running in the video will not adapt to the size changes. This means, you have to plan ahead and figure out where you want your video to be displayed and then keep the pane layout.