MPlayer's features for geeks: watching movies in a terminal

The idea of watching movies in a text console may seem weird at the beginning, but it’s not as weird as you would think. I actually used it recently two or three times as a fallback solution, that allowed me to continue watching in spite of crashed graphical environment. Because if you like to play with bleeding-edge software, things tend to blow up from time to time. And if things blow up, it’s good to have some kind of “plan B”.

Prerequisites

What I am going to describe, should work on different distributions and with different hardware configurations. I have used MPlayer (version SVN-r35920-4.8.0, but older versions should work too) with fbdev2 video output on Arch Linux, with the i915 video driver. I have also assumed the availability of Bash, ffprobe and bc (but this is not required to play videos).

And I’m going to use Big Buck Bunny for demonstrational purposes ;)

Let’s watch something

Switch to a text console (if you don’t know how, try shortcuts from Ctrl + Alt + F1, Ctrl + Alt + F2, …, and so on until you find an empty console) and log in.

Now, try to run:

mplayer -vo fbdev2 big_buck_bunny.ogg

This should already play the movie in the console, but quite probably it will be small and you will see the console output in the background. So let’s tune it a bit:

mplayer -vo fbdev2 -fs big_buck_bunny.ogg

With -fs (fullscreen) you should be able to get rid of console visible in the background. But we still need to set the correct size for the movie, and preferably we would use the whole screen.

Unfortunately, fbdev2 doesn’t know how to automatically scale the video to use all available space. We are therefore forced to specify a playback resolution for the movie, in pixels. For that, we can use the -zoom parameter. Let’s try how it works:

mplayer -vo fbdev2 -fs -zoom -x 400 -y 300 big_buck_bunny.ogg

Now your movie should use only small part of the screen - exactly 400 by 300 pixels. But we can still do it a bit better. In this case, the width of the movie will be 400 pixels, and the height will be adjusted automatically with the correct aspect ratio:

mplayer -vo fbdev2 -fs -zoom -xy 400 big_buck_bunny.ogg

And if you now use the width of your screen, e.g. -zoom -xy 1920, it’s going to work fine as long as the movie’s aspect ratio is greater or equal to your screen’s aspect ratio. But let’s say that your movie’s size is 480x384 (good old 4:3). If you try to display it with -zoom -xy 1920, MPlayer will scale it to 1920x1536, thus requiring higher resolution than you quite probably have. It’s easy to calculate the correct value of -xy parameter, but wouldn’t it be better to just automate the process?

Bash and FFmpeg for the rescue

Let’s start with the whole script:

#!/bin/bash

screen_size_x=1920
screen_size_y=1080

if [ $# -lt 1 ]; then
  echo "usage: $0 {path}"
  exit -1
fi

# obtain video size
video_info=`ffprobe -v quiet -print_format csv -show_streams "$@"|head -n1`

video_x=`echo $video_info|cut -d , -f 10`
video_y=`echo $video_info|cut -d , -f 11`

echo "Original video size: ${video_x}x${video_y}"

# calculate new size
ratio=`echo "r1 = $screen_size_x/$video_x;
             r2 = $screen_size_y/$video_y;
             if (r1 < r2) r1 else r2" |bc -l`

final_size_x=`echo "scale = 3; $video_x*$ratio" |bc -l`
final_size_y=`echo "scale = 3; $video_y*$ratio" |bc -l`

printf "Calculated video size: %.0fx%.0f\n" $final_size_x $final_size_y

mplayer -vo fbdev2 -fs -zoom -xy $final_size_x "$@"

And now slowly… Two following lines contain your screen resolution. Adjust them according to your requirements.

screen_size_x=1920
screen_size_y=1080

Here we obtain information about the video in CSV format using ffprobe (which belongs to the ffmpeg group of commands). An important assumption here is that the first available stream contains the video and not e.g. its sound. Afterwards, we’re just extracting the values that are important to us.

video_info=`ffprobe -v quiet -print_format csv -show_streams "$@"|head -n1`

video_x=`echo $video_info|cut -d , -f 10`
video_y=`echo $video_info|cut -d , -f 11`

Now it’s time to calculate the aspect ratio that we will use. We pass calculations to bc (with -l parameter to have a reasonable scale by default) and choose the ratio that allows us to fit our video on the screen.

ratio=`echo "r1 = $screen_size_x/$video_x;
             r2 = $screen_size_y/$video_y;
             if (r1 < r2) r1 else r2" |bc -l`

Finally, we calculate new height and width of the video, print it (%.0f rounds a number to the closest integer), and execute MPlayer with correct parameters.

final_size_x=`echo "$video_x*$ratio" |bc -l`
final_size_y=`echo "$video_y*$ratio" |bc -l`

printf "Calculated video size: %.0fx%.0f\n" $final_size_x $final_size_y

mplayer -vo fbdev2 -fs -zoom -xy $final_size_x "$@"

I cannot guarantee that this script is going to work on any software/hardware configuration, but since I haven’t used anything extremely weird, there’s a chance it will work in most cases.