💾 Archived View for belago.org › gemlog › ttvid.gmi captured on 2023-12-28 at 15:06:12. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

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.