Search

Ubuntu 16.04 - Rotate & Stabilize your video with MLT and Vid.stab

Contents[Hide]

dropcap-ubuntu-stabilize

Nowadays, street video shooting is becoming a reality.  With any modern smartphone, point-and-shoot camera or even a GoPro camera, you can shoot any video anywhere.

These devices are affordable, light-weight, very compact and easy to use. Whatever happens around you, you are able to record it on the spot. But, on the other end, as these devices are compact and light, they are not very steady. Your recordings tend to be shaky !

Another problem you can encounter when shooting from a smartphone is that your video may be recorded upside-down or even rotated by 90°.

Till date, I did not find any very simple solution under Linux to simply stabilize (unshake) and/or rotate my day-to-day videos.

Hopefully, thanks to MLT framework, it is possible to use a command line tool melt and some specific plugins (vid.stab to stabilize and affine to rotate) to do the job.

This article explains how to easily post-process any group of video files straight from Nautilus file manager to rotate and stabilize them. The tool handles following actions :

  • read important metadata
  • rotate video if needed
  • stabilize video if needed
  • transcode it to h264 & aac

It has been designed and tested nder Ubuntu and Ubuntu Gnome Xenial 16.04 LTS. It should be applicable to many up-to-date Linux distro.

If you don't need any technical explanation and you  just want to stabilize your video straight from Nautilus file manager, you can jump to Complete installation procedure. It will provide a complete and simple installation script.

1. Install tools

1.1. Helper tools

In the process of rotating and deshaking video file, we will be using various tools :

  • YAD (Yet Another Dialog) is a fork of Zenity with many improvements, such as custom buttons, additional dialogs, pop-up menu in notification icon and more. We will be using YAD advanced capabilities in the main transcoding script.
  • Exiftool to collect metadata from original video file (like rotation, width, height, ...) we will use exiftool.
  • x264 to handle h264 transcoding

Thanks to latest Xenial Ubuntu release, all these packages are available from official repositories :

Terminal
# sudo apt-get install libimage-exiftool-perl x264 yad

1.2. Melt with vid.stab

In official Ubuntu 16.04 repository, melt comes in a recent 6.0 version, but it has not been compiled with vid.stab filter.
It only comes with deprecated videostab2 and videostab filters.

Thanks to Olivier Banus, Melt v6.0 including vid.stab plugin v0.98b is available in sunab/kdenlive-release PPA.

As PPA are often providing troubles when upgrading distribution and as this specific PPA provides a lot of multimedia packages, I decided not to declare it as a standard PPA, but instead, I decided to extract whatever files are needed to declare the specific Melt version including vid.stab filter.

This specific version of Melt will not replace the official Xenial version. It will be installed under /opt/vidstab.

In sunab/kdenlive-release PPA, important packages are :

  • libmlt6 & libmlt++3 : mlt framework library compiled with vid.stab
  • libmlt-data : melt configuration files (including vid.stab filter declaration)
  • libvidstab1.0 : vid.stab library
  • melt : melt binary

/opt/vidstab will be the directory holding the specific melt + vid.stab version and will be organized as follow :

  • /opt/vidstab : calling script in charge of loading specific melt binary and its libraries
  • /opt/vidstab/usr/bin : melt binary
  • /opt/vidstab/usr/lib : melt libraries
  • /opt/vidstab/usr/lib/mlt : mlt framework libraries
  • /opt/vidstab/usr/share/mlt/vid.stab : vid.stab library configuration files

Once all the files are downloaded and installed, two symbolic links need to be created to populate libraries environment needed by the new melt instance :

  • /usr/lib/mlt to point on mlt framework libraries
  • /usr/share/mlt/vid.stab to point on vid.stab librariy configuration files

Last step is to declare the wrapper script that will be in charge of calling new melt version while loading the new libraries available under /opt/vidstab/usr/lib.

/opt/vidstab/melt
#!/bin/bash
# -------------------------------------------------------
#  Wrapper for melt linked with vid.stab
#
#  For installation instructions, please check
#  http://bernaerts.dyndns.org/linux/74-ubuntu/xxx-ubuntu-trusty-rotate-stabilize-video-melt-vidstab
#  
#  Revision history :
#    20/08/2016, V1.0 - Creation by N. Bernaerts
# -------------------------------------------------------

# wrap melt call to force use of libraries in /opt/mlt-vidstab/lib
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 --library-path /opt/vidstab/usr/lib /opt/vidstab/usr/bin/melt "$@"

The following script will do all the tasks described earlier :

  1. download .deb packages and scripts
  2. extract files and place them in /opt/vidstab
  3. declare symbolic links

melt-vidstab-install.sh
#!/usr/bin/env bash
# Install specific version of melt embedding vid.stab filter

# test Ubuntu or Linux Minty distribution
DISTRO=$(lsb_release -sc 2>/dev/null)
[ "${DISTRO}" != "sarah" ] && [ "${DISTRO}" != "xenial" ] && { zenity --error --text="This automatic installation script is for Ubuntu Xenial or Linux Mint Sarah only"; exit 1; }

# create /opt/mlt-vidstab directory structure
sudo mkdir --parent /opt/vidstab

# extract file from melt
wget https://launchpad.net/~sunab/+archive/ubuntu/kdenlive-release/+build/9289708/+files/melt_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb
dpkg --fsys-tarfile melt_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb | sudo tar xf - -C /opt/vidstab
rm melt_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb

# extract files from libmlt6
wget https://launchpad.net/~sunab/+archive/ubuntu/kdenlive-release/+build/9289708/+files/libmlt6_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb
dpkg --fsys-tarfile libmlt6_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb | sudo tar xf - -C /opt/vidstab
sudo ln -s /opt/vidstab/usr/lib/mlt /usr/lib/mlt
rm libmlt6_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb

# extract file from libmlt++3
wget https://launchpad.net/~sunab/+archive/ubuntu/kdenlive-release/+build/9289708/+files/libmlt++3_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb
dpkg --fsys-tarfile libmlt++3_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb | sudo tar xf - -C /opt/vidstab
rm libmlt++3_6.0.0-0ubuntu0~sunab~xenial1_amd64.deb

# extract files from libmlt-data
wget https://launchpad.net/~sunab/+archive/ubuntu/kdenlive-release/+build/9289708/+files/libmlt-data_6.0.0-0ubuntu0~sunab~xenial1_all.deb
dpkg --fsys-tarfile libmlt-data_6.0.0-0ubuntu0~sunab~xenial1_all.deb | sudo tar xf - -C /opt/vidstab
sudo ln -s /opt/vidstab/usr/share/mlt/vid.stab /usr/share/mlt/vid.stab
rm libmlt-data_6.0.0-0ubuntu0~sunab~xenial1_all.deb

# extract file from libvidstab1.0
wget https://launchpad.net/~sunab/+archive/ubuntu/kdenlive-release/+files/libvidstab1.0_0.98b-0ubuntu0~sunab~xenial1_amd64.deb
dpkg --fsys-tarfile libvidstab1.0_0.98b-0ubuntu0~sunab~xenial1_amd64.deb | sudo tar xf - -C /opt/vidstab
rm libvidstab1.0_0.98b-0ubuntu0~sunab~xenial1_amd64.deb

# install melt wrapper
sudo wget --header='Accept-Encoding:none' -O /opt/vidstab/melt https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/melt-vidstab
sudo chmod +x /opt/vidstab/melt

You can get it straight from my GitHub repository to run it :

Terminal
# wget https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/melt-vidstab-install.sh
# . ./melt-vidstab-install.sh

/opt/vidstab/melt can now be called instead of regular /usr/bin/melt and it provides vid.stab filter :

Terminal
# melt -query | grep stab
- videostab
- videostab2
# /opt/vidstab/melt -query | grep stab
- videostab
- videostab2
- vidstab

2. How to Rotate & Stabilize your Video

We now have everything to rotate and unshake our video files.

This section explains how to process files thru command line, in a step-by-step approach.

In case of trouble with the automatic script, this section will also help you to point out where the problem can be.

The stabilization process is done in 3 steps :

2.1. Collect Video Metadata

First step is done with the help of exiftool.

This tool analyse the video file and extract important metadata like image width & height or rotation tag.

Terminal
# exiftool -s3 -rotation -imagewidth -imageheight -avgbitrate input.mp4
90
1920
1080
19.1 Mbps

This video is 1920x1080, with average bitrate of 19.1 Mbits/s and is 90° rotated (it has been taken from a smartphone held vertically).

2.2. Calculate Stabilization parameters

Next step is done with the help of melt tool.

The command line tool is provided with MLT framework and it provides use 2 very powerful plugins :

  • affine to rotate & resize video if needed
  • vidstab to calculate stabilization correction parameters

You can check what stabilization plugin is available from your melt client :

Following command will start the stabilization analysis using vidstab plugin and will generate a input.mlt XML file, containing all the processing parameters :

Terminal
# melt input.mp4 -filter affinetransition.fix_rotate_x=450transition.scale_x=1transition.scale_y=1 -filter vidstab shakiness=8 smoothing=20 -consumer xml:input.mlt all=1

affine filter parameters are in blue. This filter recognises some specific parameters described in MLT Affine filter page. For example here :

  • transition.fix_rotate_x : rotation angle in degre x 5 (90° becomes 450). Don't ask me why !
  • transition.scale_x & transition.scale_y : scaling factor to apply when rotating a rectangular video to fit the largest size in the smallest one.

vidstab filter parameters are in red. This filter recognises some specific parameters described in MLT Vidstab filter page. For example here :

  • shakiness
  • smoothing

Instead of vidstab, you can also use videostab2 or videostab plugins. But quality of stabilization algorithm won't the same.

2.3. Encode Final Video

Once the input.mlt file is available, we can start the final encoding with melt second pass.

This second pass will encode the final video with the results of the first analysis pass.

For the final video, we will use :

  • video from previous stage processing
  • audio from original video

In this example, the final video will be encoded with h264 video at 5 Mbits and aac audio at 128 Kbits.

Terminal
# melt input.mlt -audio-track input.mp4 -consumer avformat:input-stab.mp4 vcodec=libx264 b=5000k acodec=aac ab=128k tune=film preset=slow

Specific x264 encoding parameters can be added at the end of the command line. Here I've added a  tune=film preset=slow parameter.

All available parameters can be found with the command x264 --fullhelp.

You now have a input-stab.mp4 file with your stabilized video !

3. Automated script

Now that we've done a stabilization process thru command line, we can create a script which will be in charge of :

  • selection of stabilization and encoding parameters
  • encoding with stabilization

Before processing the video file, you will get a dialog box to precisely define rotation & stabilization parameters.

ubuntu-video-stabilize-options

During processing, a progress dialog box keeps you informed with the video file transcoding progression.

ubuntu-video-stabilize-analyse

ubuntu-video-stabilize-encode

You can cancel the processing at any time.

Main stabilization script algorithm is quite simple :

  1. It checks that all needed tools are available
  2. It analyses all input videos to extract important metadata
  3. It asks you to define main parameters for every input video
  4. It calculates the rotation and/or stabilization parameters
  5. It encodes all final videos in a mp4 container with h264 video & aac audio

3.1. Script

Processing of input video files is done by one main script /usr/local/bin/video-stabilize .

/usr/local/bin/video-stabilize
#!/bin/bash
# -------------------------------------------------------
#  Video Stabilizer based on MLT and vid.stab
#  For installation instructions, please check
#  http://bernaerts.dyndns.org/linux/350-ubuntu-xenial-rotate-stabilize-video-melt-vidstab
#  
#  Depends on :
#    * melt (from ppa:sunab/kdenlive-release)
#    * vidstab (from ppa:sunab/kdenlive-release)
#    * yad
#    * exiftool
#    * avconv and x264
#
#  Revision history :
#    04/03/2012, V1.0 - Creation by N. Bernaerts
#    04/04/2012, V1.1 - Add codecs as parameters
#    17/01/2015, V2.0 - Completle rewrite for Ubuntu 14.04 LTS 
#                       Handle rotation as well thanks to Guy Eagling
#    19/01/2015, V2.1 - Manage per process .trf file to allow parallel execution
#    19/01/2015, V2.2 - Add .pid file to handle processing cancellation
#    23/01/2015, V3.0 - Check tools availability, 
#                       Detect available stabilization filters (vidstab, videostab2 or videostab)
#                       Add Fedora compatibility (mlt-melt) thanks to Guy Eagling
#    06/03/2015, V3.1 - Externalize parameters to ~/.config/video-stabilize.conf
#                       Add multiple files processing thanks to Hingo's idea
#    10/03/2015, V3.2 - Update exiftool handling for MKV files
#    12/03/2015, V3.3 - Add extra parameters to dialog box 
#                       Change progress calculation to avoid errors
#    29/05/2015, V3.4 - Check presence of ~/.config/video-stabilize.conf 
#    26/07/2015, V3.5 - Change options of first pass to avoid some errors (thanks to Gustavo Lapido Loureiro)
#                       Add number of thread as encoder option
#                       Kill process and parent process in case of cancellation
#    22/09/2015, V3.6 - Correction of a bug in final encoding options (thanks to Ted Bartlett)
#    21/02/2016, V3.7 - Handle scientific notation for video rate (thanks to Aslanex)
#    24/08/2016, V3.8 - Use specific build of melt for vid.stab (Ubuntu Xenial 16.04)
# -------------------------------------------------------

# -------------------------------------------------
#          Check tools availability
# -------------------------------------------------

# check /opt/mlt-vidstab/melt (specific build with vid.stab filter) or melt (ubuntu) or mlt-melt (fedora)
[ -f /opt/vidstab/melt ] && CMD_MELT="/opt/vidstab/melt" || CMD_MELT="melt"
command -v $CMD_MELT >/dev/null 2>&1 || { CMD_MELT="mlt-melt"; }
command -v $CMD_MELT >/dev/null 2>&1 || { zenity --error --text="Please install Melt from MLT framework"; exit 1; }

# check yad, exiftool and x264
command -v yad >/dev/null 2>&1 || { zenity --error --text="Please install Yad"; exit 1; }
command -v exiftool >/dev/null 2>&1 || { zenity --error --text="Please install ExifTool"; exit 1; }
command -v x264 >/dev/null 2>&1 || { zenity --error --text="Please install x264"; exit 1; }

# -------------------------------------------------------
#      Read parameters from configuration file
# -------------------------------------------------------

# Configuration file : ~/.config/video-stabilize.conf
FILE_CONF="$HOME/.config/video-stabilize.conf"

# check configuration file
[ -f "$FILE_CONF" ] || { zenity --error --text="Please create and configure ${FILE_CONF}"; exit 1; }

# Load configuration file
ARR_EXT=($(cat "${FILE_CONF}" | grep "extension" | cut -d'=' -f 2- | cut -d ";" --output-delimiter=" " -f 1-))
STAB_SHAKINESS=$(cat "${FILE_CONF}" | grep "shakiness" | cut -d'=' -f2)
STAB_SMOOTHING=$(cat "${FILE_CONF}" | grep "smoothing" | cut -d'=' -f2)
STAB_OPTZOOM=$(cat "${FILE_CONF}" | grep "optzoom" | cut -d'=' -f2)
STAB_EXTRA=$(cat "${FILE_CONF}" | grep "extra" | cut -d'=' -f2-)
VIDEO_CODEC=$(cat "${FILE_CONF}" | grep "video-codec" | cut -d'=' -f2)
AUDIO_CODEC=$(cat "${FILE_CONF}" | grep "audio-codec" | cut -d'=' -f2)
VIDEO_RATE=$(cat "${FILE_CONF}" | grep "video-rate" | cut -d'=' -f2)
AUDIO_RATE=$(cat "${FILE_CONF}" | grep "audio-rate" | cut -d'=' -f2)
ENCODE_OPTION=$(cat "${FILE_CONF}" | grep "option" | cut -d'=' -f2-)
ENCODE_THREAD=$(cat "${FILE_CONF}" | grep "thread" | cut -d'=' -f2-)

# -------------------------------------------------------
#          Retrieve or select video file
# -------------------------------------------------------

IFS=$'\n'

# loop thru arguments to check that they are video files
for arg
do
  # get file name and extension
  FILE_PATH="$arg"
  FILE_EXT=$(echo "${FILE_PATH}" | sed 's/^.*\.\(.*\)$/\1/')

  # check if file extension given in parameter is in the allowed extension list
  [ -f "$FILE_PATH" ] && EXT_OK=$(echo "${ARR_EXT[@]}" | grep --ignore-case ${FILE_EXT}) || EXT_OK=""

  # if ok, add it to the video files array
  [ -n "$EXT_OK" ] && ARR_VIDEO=("${ARR_VIDEO[@]}" "${FILE_PATH}")
done

# if there is no candidate files
if [ ${#ARR_VIDEO[@]} -eq 0 ]
then
  # generate allowed extension list
  LIST_EXT=$(echo "*.${ARR_EXT[@]}" | sed 's/ / *\./g')

  # open multiple files selection dialog box
  LST_VIDEO=$(yad --center --width=800 --height=500 --window-icon "video" --image "stabilizer" \
                  --file --multiple --file-filter="Video file (${LIST_EXT[@]})|${LIST_EXT[@]}" \
                  --title="Select video file to stabilize")

  # generate video files array
  ARR_VIDEO=($(echo "${LST_VIDEO}" | tr "|" "\n"))
fi 

# ---------------------------------------------------------
#   Analyse video files and select processing parameters
# ---------------------------------------------------------

# loop thru selected video files
for FILE_PATH in "${ARR_VIDEO[@]}"
do
  # generate temporary exif file
  FILE_EXIF=$(mktemp -t stab-XXXXXXXX.exif)

  # get video metadata
  exiftool "${FILE_PATH}" > ${FILE_EXIF}
  FILE_WIDTH=$(cat ${FILE_EXIF} | grep "^Image Width" | cut -d':' -f2 | xargs)
  FILE_HEIGHT=$(cat ${FILE_EXIF} | grep "^Image Height" | cut -d':' -f2 | xargs)
  FILE_BITRATE=$(cat ${FILE_EXIF} | grep "^Avg Bitrate" | cut -d':' -f2 | xargs)
  FILE_ROTATE=$(cat ${FILE_EXIF} | grep "^Rotation" | cut -d':' -f2 | xargs)
  [ "${FILE_BITRATE}" == "" ] && FILE_BITRATE="Unknown"
  [ "${FILE_ROTATE}" == "" ] && FILE_ROTATE="0"

  # remove temporary exif file
  rm ${FILE_EXIF}

  # get encoding parameters using local number decimal separator (, or .)
  SEPARATOR=$(printf "%'.2f" 1 | sed 's/^1\(.\).*$/\1/')
  VIDEO_RATIO=$(echo "scale=2; ${FILE_WIDTH} / ${FILE_HEIGHT}" | bc | sed 's/[\.\,]/'${SEPARATOR}'/g')
  [ "$FILE_ROTATE" = "0" -o "$FILE_ROTATE" = "180" ] && LST_RATIO="1|${VIDEO_RATIO}" || LST_RATIO="${VIDEO_RATIO}|1" 

  # detect if rotation needed
  [ "$FILE_ROTATE" = "0" ] && CHECK_ROTATE="FALSE" || CHECK_ROTATE="TRUE"

  # set title and text of dialog box
  TITLE="${FILE_PATH}"
  TEXT="Select transformation parameters :\n ( size = ${FILE_WIDTH}x${FILE_HEIGHT}, rate = ${FILE_BITRATE} )\n"

  # get list of stabilization filters available from current melt version
  ARR_FILTER=$(${CMD_MELT} -query filters | grep stab | awk '{print $2}' | sort -r)
  LST_FILTER=$(echo ${ARR_FILTER} | sed 's/ /|/g')

  # display dialog box
  CHOICE=$(yad --title "${TITLE}" --text "${TEXT}" --center --window-icon "video" --image "stabilizer" --width 500 \
    --form --item-separator='|' \
    --field="Rotate:CHK" "${CHECK_ROTATE}" \
    --field="  - Angle (${FILE_ROTATE}° detected):NUM" "${FILE_ROTATE}|0..359" \
    --field="  - Resize ratio (${VIDEO_RATIO} for 90°):CB" "${LST_RATIO}" \
    --field="Stabilize:CHK" "TRUE" \
    --field="  - Stabilization filter:CB" "${LST_FILTER}" \
    --field="  - Shakiness [ 0 ... 10 ]:NUM" "${STAB_SHAKINESS}|1..10" \
    --field="  - Smoothing [ 0 ... 100 ]:NUM" "${STAB_SMOOTHING}|0..100"  \
    --field="  - Optimal Zoom [ 0, 1, 2 ]:NUM" "${STAB_OPTZOOM}|0..2" \
    --field="  - Extra stabilize options" "${STAB_EXTRA}" \
    --field="Encoder:LBL" "final" \
    --field="  - ${VIDEO_CODEC} video bitrate (Kbits/s):NUM" "${VIDEO_RATE}|1..50000|100" \
    --field="  - ${AUDIO_CODEC} audio bitrate (Kbits/s):NUM" "${AUDIO_RATE}|1..320" \
    --field="  - Extra encoder parameters" "${ENCODE_OPTION}" )

  # retrieve parameters
  ROTATE=$(echo ${CHOICE} | cut -d'|' -f1)
  ROTATE_ANGLE=$(echo ${CHOICE} | cut -d'|' -f2)
  ROTATE_RATIO=$(echo ${CHOICE} | cut -d'|' -f3)
  STABILIZE=$(echo ${CHOICE} | cut -d'|' -f4)
  STAB_FILTER=$(echo ${CHOICE} | cut -d'|' -f5)
  STAB_SHAKINESS=$(echo ${CHOICE} | cut -d'|' -f6)
  STAB_SMOOTHING=$(echo ${CHOICE} | cut -d'|' -f7)
  STAB_OPTZOOM=$(echo ${CHOICE} | cut -d'|' -f8)
  STAB_EXTRA=$(echo ${CHOICE} | cut -d'|' -f9)
  VIDEO_RATE=$(echo ${CHOICE} | cut -d'|' -f11 | tr ',' '.' | awk '{ print sprintf("%.0f", $1); }')
  AUDIO_RATE=$(echo ${CHOICE} | cut -d'|' -f12)
  ENCODE_OPTION=$(echo ${CHOICE} | cut -d'|' -f13)

  # if it is needed, add file to processing queue
  if [ "$STABILIZE" = "TRUE" ] || [ "$ROTATE" = "TRUE" ];
  then
    ARR_FILE=("${ARR_FILE[@]}" "${FILE_PATH}")
    ARR_ROTATE=("${ARR_ROTATE[@]}" "${ROTATE}")
    ARR_ROTATE_ANGLE=("${ARR_ROTATE_ANGLE[@]}" "${ROTATE_ANGLE}")
    ARR_ROTATE_RATIO=("${ARR_ROTATE_RATIO[@]}" "${ROTATE_RATIO}")
    ARR_STABILIZE=("${ARR_STABILIZE[@]}" "${STABILIZE}")
    ARR_STAB_FILTER=("${ARR_STAB_FILTER[@]}" "${STAB_FILTER}")
    ARR_STAB_SHAKINESS=("${ARR_STAB_SHAKINESS[@]}" "${STAB_SHAKINESS}")
    ARR_STAB_SMOOTHING=("${ARR_STAB_SMOOTHING[@]}" "${STAB_SMOOTHING}")
    ARR_STAB_OPTZOOM=("${ARR_STAB_OPTZOOM[@]}" "${STAB_OPTZOOM}")
    ARR_STAB_EXTRA=("${ARR_STAB_EXTRA[@]}" "${STAB_EXTRA}")
    ARR_VIDEO_RATE=("${ARR_VIDEO_RATE[@]}" "${VIDEO_RATE}")
    ARR_AUDIO_RATE=("${ARR_AUDIO_RATE[@]}" "${AUDIO_RATE}")
    ARR_ENCODE_OPTION=("${ARR_ENCODE_OPTION[@]}" "${ENCODE_OPTION}")
  fi
done

# -------------------------------------------------------
#     Process files for rotation and stabilization 
# -------------------------------------------------------

# loop thru video files to process
NUM_FILE=${#ARR_FILE[@]}
for ((INDEX=0; INDEX < NUM_FILE; INDEX++))
do
  # --------------------------------
  #         Get file data
  # --------------------------------
  # get current file path 
  FILE_PATH="${ARR_FILE[$INDEX]}"

  # generate the filenames
  FILE_BASE="$(echo "${FILE_PATH}" | sed 's/^\(.*\)\..*$/\1/')"
  FILE_STAB="${FILE_BASE}-stab.mp4"

  # generate temporary files
  DIR_TMP=$(mktemp -d "$HOME/.stab-XXXXXXXX")
  FILE_TRF="${DIR_TMP}/video.trf"
  FILE_PID="${DIR_TMP}/video.pid"
  FILE_MLT="${DIR_TMP}/video.mlt"
  FILE_LOG="${DIR_TMP}/video.log"

  # get parameters
  ROTATE="${ARR_ROTATE[$INDEX]}"
  ROTATE_ANGLE="${ARR_ROTATE_ANGLE[$INDEX]}"
  ROTATE_RATIO="${ARR_ROTATE_RATIO[$INDEX]}"
  STABILIZE="${ARR_STABILIZE[$INDEX]}"
  STAB_FILTER="${ARR_STAB_FILTER[$INDEX]}"
  STAB_SHAKINESS="${ARR_STAB_SHAKINESS[$INDEX]}"
  STAB_SMOOTHING="${ARR_STAB_SMOOTHING[$INDEX]}"
  STAB_OPTZOOM="${ARR_STAB_OPTZOOM[$INDEX]}"
  STAB_EXTRA="${ARR_STAB_EXTRA[$INDEX]}"
  VIDEO_RATE="${ARR_VIDEO_RATE[$INDEX]}"
  AUDIO_RATE="${ARR_AUDIO_RATE[$INDEX]}"
  ENCODE_OPTION="${ARR_ENCODE_OPTION[$INDEX]}"

  (
  # initilize transformation arrays
  unset ARR_STABILIZE
  unset ARR_ROTATE
  unset ARR_ENCODE

  # ------------------------------------------------
  #    PREPARATION : Setup processing parameters
  # ------------------------------------------------

  # initial display
  echo "# Computing parameters"
  echo "0"

  # if needed, generate stabilizer parameters array
  ARR_EXTRA=($(echo "${STAB_EXTRA}" | cut -d ";" --output-delimiter=" " -f 1-))
  [ "$STABILIZE" = "TRUE" ] && ARR_STABILIZE=("-filter" "${STAB_FILTER}" "filename=${FILE_TRF}" "shakiness=${STAB_SHAKINESS}" \
                                              "smoothing=${STAB_SMOOTHING}" "optzoom=${STAB_OPTZOOM}" "${ARR_EXTRA[@]}")

  # if needed, set rotation filter
  if [ "$ROTATE" = "TRUE" ]
  then
    # convert angle for filter use
    X_ANGLE=$((10 * ${ROTATE_ANGLE} / 2))

    # set rotation filter
    ARR_ROTATE=("-filter" "affine" "transition.fix_rotate_x=${X_ANGLE}")

    # if different than 1, set transformation ratio
    [ "${ROTATE_RATIO}" != "1" ] && ARR_ROTATE=("${ARR_ROTATE[@]}" "transition.scale_x=${ROTATE_RATIO}" "transition.scale_y=${ROTATE_RATIO}")
  fi

  # ----------------------------------------------
  #   PASS 1 : Rotation / Stabilization analysis
  # ----------------------------------------------

  # information display
  echo "# Analysing file"

  # launch analysis command
  ${CMD_MELT} -progress "${FILE_PATH}" ${ARR_ROTATE[@]} ${ARR_STABILIZE[@]} -consumer xml:"${FILE_MLT}" all=1 2>"${FILE_LOG}" &

  # save current process and melt command process id
  PID=$(ps aux | grep "${CMD_MELT}" | grep "${FILE_PATH}" | awk '{print $2}')
  echo "${BASHPID}" > "${FILE_PID}"
  echo "${PID}" >> "${FILE_PID}"

  while [ "$PID" != "" ] 
  do    
    # check if process is still running
    PID=$(ps aux | awk '{print $2}' | grep ${PID})

    # calculate process completion
    LOG_LINE="$(tail --bytes=50 ${FILE_LOG} | grep 'Frame' | grep 'percentage')"
    LOG_FRAME=$(echo "${LOG_LINE}" | sed 's/^.*Frame[ :]*\([0-9]*\).*$/\1/')
    LOG_PERCENT=$(echo "${LOG_LINE}" | sed 's/^.*percentage[ :]*\([0-9]*\).*$/\1/')

    # if percentage has been retrieved from log, display process completion
    [[ ${LOG_FRAME} == +([0-9]) ]] && echo "# Analysing frame ${LOG_FRAME}"
    [[ ${LOG_PERCENT} == +([0-9]) ]] && echo $((${LOG_PERCENT} / 2))

    # wait for 2 seconds
    sleep 2
  done

  # ------------------------------------------
  #   PASS 2 : Final result encoding
  # ------------------------------------------

  # information display
  echo "# Generating file"

  # generate encoder parameters array
  ARR_OPTION=($(echo "${ENCODE_OPTION}" | cut -d ";" --output-delimiter=" " -f 1-))
  ARR_ENCODE=("vcodec=${VIDEO_CODEC}" "b=${VIDEO_RATE}k" "acodec=${AUDIO_CODEC}" "ab=${AUDIO_RATE}k" "${ARR_OPTION[@]}" )

  # launch generation command
  ${CMD_MELT} -progress "${FILE_MLT}" -audio-track "${FILE_PATH}" -consumer avformat:"${FILE_STAB}" ${ARR_ENCODE[@]} real_time=-${ENCODE_THREAD} 2>"${FILE_LOG}" &

  # save current process and melt command process id
  PID=$(ps aux | grep "${CMD_MELT}" | grep "${FILE_MLT}" | awk '{print $2}')
  echo "${BASHPID}" > "${FILE_PID}"
  echo "${PID}" >> "${FILE_PID}"

  # follow the stabilization progress
  while [ "$PID" != "" ] 
  do    
    # check if process is still running
    PID=$(ps aux | awk '{print $2}' | grep ${PID})

    # calculate process completion
    LOG_LINE="$(tail --bytes=50 ${FILE_LOG} | grep 'Frame' | grep 'percentage')"
    LOG_FRAME=$(echo "${LOG_LINE}" | sed 's/^.*Frame[ :]*\([0-9]*\).*$/\1/')
    LOG_PERCENT=$(echo "${LOG_LINE}" | sed 's/^.*percentage[ :]*\([0-9]*\).*$/\1/')

    # if percentage has been retrieved from log, display process completion
    [[ ${LOG_FRAME} == +([0-9]) ]] && echo "# Generating frame ${LOG_FRAME}"
    [[ ${LOG_PERCENT} == +([0-9]) ]] && echo $((50 + (${LOG_PERCENT} / 2)))

    # wait for 2 seconds
    sleep 2
  done

  # remove PID file
  rm "${FILE_PID}"

  # declare end of processing
  echo "# File processed and available"
  echo "100"
  ) | yad --center --width=600 --window-icon "video" --image "stabilizer" --progress --auto-close --title "[$((${INDEX} + 1))/${NUM_FILE}] ${FILE_PATH}"

  # -----------------------------------------
  #   END : Final process and files cleanup
  # -----------------------------------------

  # if process is still running (operation has been canceled), kill the process
  [ -f "${FILE_PID}" ] && kill -9 $( cat "${FILE_PID}" )

  #  cleaning-up of all temporary files
  rm -R ${DIR_TMP}

done

This script uses a configuration file (described below) and its own icon.

To install the script, its default configuration and declare the icon, just run these commands :

Terminal
# mkdir -p $HOME/.config
# wget -O $HOME/.config/video-stabilize.conf https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/video-stabilize.conf
# sudo wget -O /usr/local/bin/video-stabilize https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/video-stabilize
# sudo chmod +x /usr/local/bin/video-stabilize
# sudo wget -O /usr/share/icons/stabilizer.png https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/stabilizer.png

3.2. Configuration

All important parameters of this script are defined in ~/.config/video-stabilize.conf configuration file.

These parameters include

  • stabilization standard options (shakiness, smoothing, optzoom)
  • stabilization advanced options
  • video & audio codec (should not be modified)
  • video & audio default bitrate
  • x264 advanced options
  • number of threads to use during h264 encoding

~/.config/video-stabilize.conf
[file]
extension=3gp;avi;dv;m4v;mov;mkv;movie;mp4;mpeg;mpg;qt

[stabilize]
shakiness=4
smoothing=15
optzoom=1
extra=show=0;crop=0

[encoder]
video-codec=libx264
audio-codec=aac
video-rate=20000
audio-rate=128
option=tune=film;preset=slow
thread=1

These parameters are quite self explanatory and are coming from vidstab to set stabilization correction parameters and from x264 for h264 encoding .

By default, number of threads to use during final encoding is set to thread=1. If your processor is multi-core, it is advisable to set the number of threads to your number of cores - 1.

You can get your processor number of cores with this simple command :

Terminal
# nproc
4

To modify  if you want to modify any default parameter just edit this file.

4. Desktop Integration

It is now time to fully integrate video rotate & stabilization in your desktop environment.

4.1. Menu declaration

To get Video Rotation and Stabilization tool available from your desktop Application / Sound & Video menu, you just need to declare /usr/share/applications/video-stabilize.desktop.

/usr/share/applications/video-stabilize.desktop
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=/usr/local/bin/video-stabilize
Name=Video rotation and stabilization
Categories=GNOME;AudioVideo;AudioVideoEditing;
MimeType=video/*;
Icon=stabilizer

It will be avaibale from Application / Sound & Video menu.

If you start Video Rotation and Stabilization you'll then be able to :

  • select one or multiple video files
  • set stabilization and encoding parameters for every selected file
  • process every selected file according to its individual parameters

4.2. Nautilus integration

To be able to add extensions to Nautilus right click menu on a file, you need to install nautilus-actions extensions, which is not installed by default under Ubuntu.

Terminal
# sudo apt-get install nautilus-actions

You will then be able to start the auto-rotation & stabilization of any video file from a simple right click in Nautilus.

ubuntu-video-stabilize-menu

Then, to get a right click menu entry on any video file from Nautilus, you need to declare ~/.local/share/file-manager/actions/video-stabilize-action.desktop specific action.

~/.local/share/file-manager/actions/video-stabilize-action.desktop
[Desktop Entry]
Type=Action
Icon=stabilizer
Name[C]=Rotation and stabilization
Name[en]=Rotation and stabilization
Name[en_US]=Rotation and stabilization
Name[fr_FR]=Rotation et stabilisation 
Tooltip[C]=Tool to rotate and stabilize video shootings
Tooltip[en]=Tool to rotate and stabilize video shootings
Tooltip[en_US]=Tool to rotate and stabilize video shootings
Tooltip[fr_FR]=Outil de rotation et de stabilisation de video
Profiles=stabilize_video;

[X-Action-Profile stabilize_video]
Exec=video-stabilize %F
MimeTypes=video/*;
Capabilities=Local
Name[C]=Default profile
Name[en]=Default profile
Name[en_US]=Default profile
Name[fr_FR]=Profil par défaut

This will make the Video Rotation and Stabilization tool accessible from the right menu on any video file whose mimetypes is declared in the .desktop file.

To install the package and declare the .desktop files, just run these commands :

Terminal
# sudo wget -O /usr/share/applications/video-stabilize.desktop https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/video-stabilize.desktop
# mkdir --parents $HOME/.local/share/file-manager/actions
# wget -O $HOME/.local/share/file-manager/actions/video-stabilize-action.desktop https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/video-stabilize-action.desktop

5. Complete installation procedure

If you want to install all needed tools and configuration files in one go, you can run an all-in-one installation script.

This script has been written for Ubuntu 16.04. It will do whatever operation have been described earlier in this article.

Terminal
# wget https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/video-stabilize-install.sh
# chmod +x video-stabilize-install.sh
# ./video-stabilize-install.sh

After next login, you should be able to rotate, stabilize and re-encode your video files from a simple right click.

In case you detect any bug or if you have some update ideas which can benefit everybody, don't hesitate to contact me by email or to fork it on GitHub.

 

Hope it helps.

Signature Technoblog

This article is published "as is", without any warranty that it will work for your specific need.
If you think this article needs some complement, or simply if you think it saved you lots of time & trouble,
just let me know at This email address is being protected from spambots. You need JavaScript enabled to view it.. Cheers !

icon linux icon debian icon apache icon mysql icon php icon piwik icon googleplus