Search

Ubuntu - Transcode your video to MKV / AAC the simple way

Contents[Hide]

dropcap-ubuntu-stabilize

If you sometimes end up grabbing some video files from internet, you may have encountered some playback troubles :

  • Video container may not be playable on some devices (AVI, MOV, ...)
  • Some copyrighted audio codecs like DTS, AC3, E-AC3, ... may give play back problem on some of your devices
  • On multi-channels audio tracks, general audio level may vary widely between talks and action scenes (you end up changing volume level at every scene change)

So, to be able to play your video on any type of device and in any type of environment, an elegant option is to :

  • use MKV container as it is open source and recognized by almost all modern players
  • convert all audio tracks to AAC as it is playable on almost any modern devices
  • add some midnight mode audio channels side to the multi-tracks channels to allow smooth listening even without a home cinema system

This article explains how to setup a post-processing environment for your Linux desktop to be able to :

  • generate MKV video file from any video file
  • convert all audio tracks to AAC format (stereo and multi-channels)
  • add some associated Midnight Mode audio tracks (if selected)
  • add an embedded video cover (if present)

It also explains how to use this tool straight from your desktop menu and from Nautilus file manager. A simple right click on a video file will show a menu to post-process it.

It has been designed and tested on an Ubuntu 14.04 LTS workstation, but it should be applicable to any Linux distribution, as long as the needed tools are available.

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

1. Install Packages

Main transcoding script uses various tools :

  • yad, a fork of zenity, to display advanced selection dialog boxes
  • mediainfo to read video files characteristics
  • avconv to convert audio tracks to plain WAV
  • sox (a sound processing swiss army knife) to generate midnightmode audio tracks by applying DRC and normalization
  • fdkaac (based on fdk-aac) to transcode audio tracks to ACC (best transcoder at the time of this article)
  • mkvmerge to extract audio tracks and to multiplex final MKV file

As yad is not available in Ubuntu official repositories, we need to install it thru PPA WebUpd8.

Terminal
# sudo add-apt-repository ppa:webupd8team/y-ppa-manager
# sudo apt-get update
# sudo apt-get install yad

Same operation with fdkaac, which is not yet available in Ubuntu official repositories.

Terminal
# sudo add-apt-repository -y ppa:mc3man/fdkaac-encoder
# sudo apt-get update
# sudo apt-get install fdkaac-encoder aac-enc

All other tools are available in official repositories and can be directly installed :

Terminal
# sudo apt-get install mediainfo libav-tools sox mkvtoolnix

2. Transcoding script

We now have everything to transcode audio tracks embedded in various video files and to generate some midnight mode version of these tracks.

Audio tracks transcoding procedure is following these simple steps :

  • it checks all tools availability
  • if no input file is given, it proposes a file selection dialog box
  • it allows to select encoding rates (different if stereo, multi-channels or midnight mode)
  • if already AAC, tracks are kept untouched
  • if not AAC, audio tracks are transcoded to AAC
  • if selected, midnight mode tracks are generated side to the original ones
  • all audio tracks are multiplexed back to a final MKV file

ubuntu mkvaac select parameters

For embedded tracks other than audio, behaviour is as follow :

  • all subtitle tracks are kept untouched
  • all attachments are removed
  • if a video cover is found, it is added as a "cover" attachment
  • general video name is deduced from the filename

When looking for video cover, the script looks for an image file in video file directory in this order :

  1. VideoFilename.tbn
  2. cover.jpg
  3. folder.jpg

Transcoding script provides a different behaviour when launched with a single video file or with multiple files to process :

  • In case of a single file, it allows a fine tuning of audio tracks. It proposes you to keep or drop original audio tracks (they will be transcoded if non AAC) and it offers the possibilty to select whichever audio track should be transcoded as a complementary midnight mode track.
  • In case of multiple files, no selection is available. It works in batch mode. All audio tracks are processed and converted to ACC and no midnight mode complementary track is generated.

ubuntu mkvaac select tracks

During transcoding process (which may takes a long time according to number of tracks to convert), a progress dialog keeps you informed of current step.

ubuntu mkvaac progress

Main default parameters are defined in ~/.config/video-convert2mkvaac.conf configuration file.

Parameters are self explanatory :

  • different encoding rates (in kbits/s)
  • video cover extension

So if you want to modify any default parameter, just edit this file before running the tool.

~/.config/video-convert2mkvaac.conf
[rate]
available=64|128|160|192|256|384
midnight=160
stereo=192
multi=384

[cover]
extension=tbn

Transcoding script should be placed under /usr/local/bin/video-convert2mkvaac :

/usr/local/bin/video-convert2mkvaac
#!/bin/bash
# -------------------------------------------------------
#  Convert video to MKV container and
#   transcode audio to AAC with optionnal midnight mode audio track
#  
#  Usage is explained at http://bernaerts.dyndns.org/linux/74-ubuntu/336-ubuntu-transcode-video-mkv-aac-nautilus
#
#  Depends on :
#    * yad (from ppa:webupd8team/y-ppa-manager)
#    * mediainfo
#    * avconv (libav-tools)
#    * sox
#    * fdkaac (from ppa:fdkaac-encoder)
#    * mkvmerge (mkvtoolnix)
#  
#  Revision history :
#    23/01/2015, V1.0 - Creation by N. Bernaerts
#    24/01/2015, V1.1 - Properly handle progress cancellation
#                       Change video file detection algorithm
#    19/07/2015, V2.0 - Handle multiple file selection
#                       Add GUI mode to select tracks
#                       and to add midnight mode tracks
#    20/07/2015, V2.1 - Switch to YAD and select rates
#    12/12/2015, V2.2 - Make track langage editable
#    13/12/2015, V2.3 - Add default track selection
#    18/12/2015, V2.4 - Correct nasty bug with PID < 10000
#    03/06/2016, V2.5 - Remove any multi-threaded option to avoid audio time shift
#    05/06/2016, V2.6 - Add audio tracks description
# -------------------------------------------------------

IFS=$'\n'

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

# check mediainfo, mkvmerge, avconv and fdkaac
command -v yad >/dev/null 2>&1 || { zenity --error --text="Please install yad [yad from ppa:webupd8team/y-ppa-manager]"; exit 1; }
command -v mediainfo >/dev/null 2>&1 || { zenity --error --text="Please install mediainfo"; exit 1; }
command -v avconv >/dev/null 2>&1 || { zenity --error --text="Please install avconv [libav-tools]"; exit 1; }
command -v sox >/dev/null 2>&1 || { zenity --error --text="Please install sox"; exit 1; }
command -v fdkaac >/dev/null 2>&1 || { zenity --error --text="Please install fdkaac [fdkaac-encoder from ppa:mc3man/fdkaac-encoder]"; exit 1; }
command -v mkvmerge >/dev/null 2>&1 || { zenity --error --text="Please install mkvmerge [mkvtoolnix]"; exit 1; }

# -------------------------------------------------------
#  Read configuration
# -------------------------------------------------------

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

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

# Load configuration
RATE_AVAILABLE=$(cat "${FILE_CONF}" | grep "available" | cut -d'=' -f2)
RATE_DRC=$(cat "${FILE_CONF}" | grep "midnight" | cut -d'=' -f2)
RATE_STEREO=$(cat "${FILE_CONF}" | grep "stereo" | cut -d'=' -f2)
RATE_MULTI=$(cat "${FILE_CONF}" | grep "multi" | cut -d'=' -f2)
COVER_EXT=$(cat "${FILE_CONF}" | grep "extension" | cut -d'=' -f2)

# -------------------------------------------------------
#  Generate list of video files to process
# -------------------------------------------------------

# loop thru arguments to retrieve video list
for arg
do
  ARR_VIDEO=("${ARR_VIDEO[@]}" "$arg")
done

# if there is no candidate files, prompt for file selection
[ ${#ARR_VIDEO[@]} -eq 0 ] && VIDEO_FILE=( "$(zenity --title="Select video file to convert" --file-selection)" )
[ -f "${VIDEO_FILE}" ] && ARR_VIDEO=( "${VIDEO_FILE}" )

# if still no file selected, exit
[ ${#ARR_VIDEO[@]} -eq 0 ] && exit 1

# set GUI mode
[ ${#ARR_VIDEO[@]} -eq 1 ] && GUI_MODE="ON" || GUI_MODE="OFF"

# -------------------------------------------------------
#  Select encoding rates
# -------------------------------------------------------

# set main parameters
ARR_PARAM_CONFIG=( "--field=${#ARR_VIDEO[@]} video file(s) will be processed:LBL" "files" "--field=Transcode rates (kbits/s):LBL" "rates" "--field=  - Midnight mode:CB" "${RATE_DRC}|${RATE_AVAILABLE}" "--field=  - Stereo:CB" "${RATE_STEREO}|${RATE_AVAILABLE}" "--field=  - Multi channels:CB" "${RATE_MULTI}|${RATE_AVAILABLE}")

# if only one file is selected, propose track selection
[ ${#ARR_VIDEO[@]} -eq 1 ] && ARR_PARAM_CONFIG=("${ARR_PARAM_CONFIG[@]}" "--field=Select Audio Tracks:CHK" "TRUE")

# display dialog box selection
CHOICE=$(yad --center --width=350 --height=200 --window-icon "video" --image "video" --title="MKV/AAC multiplexer" --form --item-separator='|' "${ARR_PARAM_CONFIG[@]}")

# get parameters
[ "${CHOICE}" = "" ] && exit 1
RATE=$(echo "${CHOICE}" | cut -d'|' -f3)
[ "${RATE}" != "" ] && RATE_DRC="${RATE}"
RATE=$(echo "${CHOICE}" | cut -d'|' -f4)
[ "${RATE}" != "" ] && RATE_STEREO="${RATE}"
RATE=$(echo "${CHOICE}" | cut -d'|' -f5)
[ "${RATE}" != "" ] && RATE_MULTI="${RATE}"
GUI_MODE=$(echo "${CHOICE}" | cut -d'|' -f6)

(

# -------------------------------------------------------
#  Main loop to process video files
# -------------------------------------------------------

for FILE_PATH in "${ARR_VIDEO[@]}"
do
  # ---------------------------------------------------------------------
  # variable initialisation
  # ---------------------------------------------------------------------

  # we assume that video track is 0 by default (may be 1 for certain formats)
  TRACK_SHIFT=0

  # initialize file list with original file (for video track)
  ARR_FILE=("0:0")

  # initialize arrays
  ARR_AAC_ID=( )
  ARR_PARAM_AAC=( )
  ARR_PARAM_AUDIO=( )
  ARR_PARAM_COVER=( )

  # -------------------------------------------------------
  #  Generate file names
  # -------------------------------------------------------

  FILE_BASE="$(echo "${FILE_PATH}" | sed 's/^\(.*\)\..*$/\1/')"
  FILE_NAME="$(echo "${FILE_PATH}" | sed 's/^.*\/\(.*\)\..*$/\1/')"
  FILE_EXT="$(echo "${FILE_PATH}" | sed 's/^.*\.\(.*\)$/\1/')"
  FILE_DIR=$(dirname "${FILE_PATH}")
  FILE_ORG="${FILE_BASE}-org.${FILE_EXT}"
  FILE_MKV="${FILE_BASE}.mkv"
  FILE_INFO="${FILE_BASE}.txt"

  FILE_COVER="${FILE_BASE}.${COVER_EXT}"
  [ -f "${FILE_COVER}" ] || FILE_COVER="${FILE_DIR}/cover.jpg"
  [ -f "${FILE_COVER}" ] || FILE_COVER="${FILE_DIR}/folder.jpg"

  # -------------------------------------------------------
  # Analyse video file
  # -------------------------------------------------------

  # get file properties
  mediainfo "${FILE_PATH}" > "${FILE_INFO}" 

  # if file is a video file it is processed
  IS_VIDEO=$(cat "${FILE_INFO}" | grep "^Video")
  if [ "${IS_VIDEO}" != "" ]
  then

    # ---------------------------------------------------------------------
    # loop thru mediainfo file to analyse file tracks
    # ---------------------------------------------------------------------

    ARR_TRACK=( )
    while read LINE           
    do 
      # check if current line holds data (xxxx   : yyyyyy)
      LINE_DATA="$(echo "$LINE" | grep ":")"

      # if line is empty, end of section 
      if [ "$LINE" = "" ]      
      then    
        # save collected data according to previous track type
        case $TRACK_TYPE in
          # video track : track shift is set according to video index as it should start from 0
          Video)
            echo "# ${FILE_NAME} - Video #${TRACK_ID} detected"
            TRACK_SHIFT=$TRACK_ID 
            ;;
          # audio track : if AAC, add it to the candidate list, if not, add it to the transcode candidate list
          Audio) 
            echo "# ${FILE_NAME} - Audio #${TRACK_ID} detected (${TRACK_FORMAT})"
            ARR_TRACK=("${ARR_TRACK[@]}" "$TRACK_ID|$TRACK_LANGUAGE|$TRACK_FORMAT|$TRACK_CHANNEL|$TRACK_RATE|$TRACK_DEFAULT|$TRACK_DELAY|$TRACK_TITLE")
            ;;
          # subtitle track : nothing special to do
          Text)   
            echo "# ${FILE_NAME} - Subtitle #${TRACK_ID} detected (${TRACK_FORMAT})"
            ;;
          *) 
            ;;
        esac

        # reset data for next track
        TRACK_TYPE=""
        TRACK_ID=""
        TRACK_LANGUAGE="und"
        TRACK_FORMAT=""
        TRACK_CHANNEL=""
        TRACK_RATE=""
        TRACK_DEFAULT="No"
        TRACK_TITLE=""
        TRACK_DELAY="0"

      # else if current line is holding track data
      elif [ "$LINE_DATA" != "" ]
      then
        # read header and data from current line
        TRACK_HEAD="$(echo "$LINE" | sed 's/^\(.*\)[ ]*: .*$/\1/g' | tr -d "/() ")"
        TRACK_DATA="$(echo "$LINE" | sed 's/^.*[ ]*: \(.*\)$/\1/g')"

        # extract data from current line
        case $TRACK_HEAD in
          ID)       TRACK_ID=$((TRACK_DATA - TRACK_SHIFT)) ;;
          Language) TRACK_LANGUAGE="${TRACK_DATA}" ;;
          Format)   TRACK_FORMAT="${TRACK_DATA}" ;;
          Channels) TRACK_CHANNEL="$(echo ${TRACK_DATA} | cut -d' ' -f1)" ;;
          Bitrate)  TRACK_RATE="${TRACK_DATA}" ;;
          Default)  TRACK_DEFAULT="${TRACK_DATA}" ;;
          Title)    TRACK_TITLE="${TRACK_DATA}" ;;
          Delayrelativetovideo) TRACK_DELAY="$(echo "${TRACK_DATA}" | sed 's/^\([-0-9]*\).*$/\1/g')" ;;
          *) ;;
        esac

      # else current line is a track header
      else
        # track type is the first word of the header line
        TRACK_TYPE=$(echo "$LINE" | sed 's/^\([a-zA-Z]*\).*$/\1/')

      fi          
    done < "${FILE_INFO}"

    # ---------------------------------------------------------------------
    # loop thru audio tracks to select tracks to keep in target video
    # ---------------------------------------------------------------------

    ARR_SELECT=( )
    for TRACK in "${ARR_TRACK[@]}"
    do
      # get track characteristics
      TRACK_ID=$(echo "$TRACK" | cut -d'|' -f1)
      TRACK_LANGUAGE=$(echo "$TRACK" | cut -d'|' -f2)
      TRACK_FORMAT=$(echo "$TRACK" | cut -d'|' -f3)
      TRACK_CHANNEL=$(echo "$TRACK" | cut -d'|' -f4)
      TRACK_RATE=$(echo "$TRACK" | cut -d'|' -f5)
      TRACK_DEFAULT=$(echo "$TRACK" | cut -d'|' -f6)
      TRACK_TITLE=$(echo "$TRACK" | cut -d'|' -f8)

      # set if track is a default one
      [ ${TRACK_DEFAULT} = "Yes" ] && TRACK_DEFAULT="TRUE" || TRACK_DEFAULT="FALSE" 

      # add current track to dialog selection array
      ARR_SELECT=("${ARR_SELECT[@]}" "${TRACK_ID}" "${TRACK_DEFAULT}" "TRUE" "FALSE" "${TRACK_LANGUAGE}" "${TRACK_FORMAT}" "${TRACK_CHANNEL}" "${TRACK_RATE}" "${TRACK_TITLE}") 

      # set current track as candidate, without midnight mode and given langage (${TRACK_TITLE})
      ARR_DEFAULT[${TRACK_ID}]="${TRACK_DEFAULT}"
      ARR_LANGAGE[${TRACK_ID}]="${TRACK_LANGAGE}"
      ARR_CANDIDATE[${TRACK_ID}]="TRUE"
      ARR_NIGHTMODE[${TRACK_ID}]="FALSE"
    done

    # if GUI mode, 
    if [ "${GUI_MODE}" = "TRUE" ] 
    then
      # dialog box to select audio tracks to mux
      ARR_COLUMN=( "--column=Number:NUM" "--column=Default:RD" "--column=Select:CHK" "--column=Midnight:CHK" "--column=Langage:TEXT" "--column=Format:TEXT" "--column=Channels:NUM" "--column=Rate:NUM" "--column=Description:TEXT" )
      ARR_CHOICE=( $(yad --center --title "${FILE_NAME}" --text="Select tracks to mux in final MKV container.\nTo get list of available langages, please use following command :\n  # mkvmerge --list-languages" --width=700 --height=300 --list --editable --print-all "${ARR_COLUMN[@]}" "${ARR_SELECT[@]}") )

      # if dialog has been canceled, exit
      [[ -z "${ARR_CHOICE[0]}" ]] && exit 0

      # loop thru choices to setup selected tracks and midnight mode tracks
      for CHOICE in "${ARR_CHOICE[@]}"
      do
        # get choices
        TRACK_ID=$(echo "$CHOICE" | cut -d'|' -f1)
        TRACK_DEFAULT=$(echo "$CHOICE" | cut -d'|' -f2)
        TRACK_CANDIDATE=$(echo "$CHOICE" | cut -d'|' -f3)
        TRACK_NIGHTMODE=$(echo "$CHOICE" | cut -d'|' -f4)
        TRACK_LANGAGE=$(echo "$CHOICE" | cut -d'|' -f5)

        # set track as selected and/or midnight mode and given langage
        ARR_DEFAULT[${TRACK_ID}]="${TRACK_DEFAULT}"
        ARR_CANDIDATE[${TRACK_ID}]="${TRACK_CANDIDATE}"
        ARR_NIGHTMODE[${TRACK_ID}]="${TRACK_NIGHTMODE}"
        ARR_LANGAGE[${TRACK_ID}]="${TRACK_LANGAGE}"
      done
    fi

    # ---------------------------------------------------------------------
    # loop thru tracks to apply AAC conversion and DRC
    # ---------------------------------------------------------------------

    NEWTRACK_INDEX=1
    for TRACK in "${ARR_TRACK[@]}"
    do
      # get track characteristics
      TRACK_ID=$(echo "$TRACK" | cut -d'|' -f1)
      TRACK_FORMAT=$(echo "$TRACK" | cut -d'|' -f3)
      TRACK_CHANNEL=$(echo "$TRACK" | cut -d'|' -f4)
      TRACK_DELAY=$(echo "$TRACK" | cut -d'|' -f7)
      TRACK_TITLE=$(echo "$TRACK" | cut -d'|' -f8)

      # get if track is selected, with midnight mode and its langage
      TRACK_DEFAULT=${ARR_DEFAULT[${TRACK_ID}]}
      TRACK_LANGUAGE=${ARR_LANGAGE[${TRACK_ID}]}
      TRACK_CANDIDATE=${ARR_CANDIDATE[${TRACK_ID}]}
      TRACK_NIGHTMODE=${ARR_NIGHTMODE[${TRACK_ID}]}

      # generate temporary filenames
      FILE_TMP_MKA="${FILE_BASE}-${TRACK_ID}.mka"
      FILE_TMP_WAV="${FILE_BASE}-${TRACK_ID}.wav"
      FILE_TMP_AAC="${FILE_BASE}-${TRACK_ID}.m4a"
      FILE_DRC_WAV="${FILE_BASE}-${TRACK_ID}-drc.wav"
      FILE_DRC_AAC="${FILE_BASE}-${TRACK_ID}-drc.m4a"
      FILE_NRM_WAV="${FILE_BASE}-${TRACK_ID}-nrm.wav"

      # if track is selected
      if [ "${TRACK_CANDIDATE}" = "TRUE" ]
      then
        # if format is already AAC, add current track ID to AAC track array
        if [ "${TRACK_FORMAT}" = "AAC" ]
        then
          # add current track ID to the array of AAC tracks
          ARR_AAC_ID=("${ARR_AAC_ID[@]}" "${TRACK_ID}")

          # determine if current track is default audio
          [ ${TRACK_DEFAULT} = "TRUE" ] && ARR_PARAM_AAC=("${ARR_PARAM_AAC[@]}" "--default-track" "${TRACK_ID}:1") || ARR_PARAM_AAC=("${ARR_PARAM_AAC[@]}" "--default-track" "${TRACK_ID}:0")

          # generate track langage and name option
          ARR_PARAM_AAC=("${ARR_PARAM_AAC[@]}" "--language" "${TRACK_ID}:${TRACK_LANGUAGE}" "--track-name" "${TRACK_ID}:${TRACK_LANGUAGE} (${TRACK_CHANNEL} channels)")
        
        # else format is not AAC, convert it to AAC
        else
          # extract audio track to MKA audio file
          echo "# ${FILE_NAME} - Audio #${TRACK_ID} : Extraction of ${TRACK_FORMAT} stream"
          mkvmerge -o "${FILE_TMP_MKA}" --no-video --audio-tracks ${TRACK_ID} --no-subtitles --no-attachments --no-global-tags --no-chapters --no-track-tags --no-buttons "${FILE_PATH}"

          # convert track to WAV format
          echo "# ${FILE_NAME} - Audio #${TRACK_ID} : Conversion to WAV"
          avconv -y -i "${FILE_TMP_MKA}" "${FILE_TMP_WAV}"

          # determine encoding rate
          [ $TRACK_CHANNEL -ge 5 ] && TRACK_RATE=$RATE_MULTI || TRACK_RATE=$RATE_STEREO

          # convert WAV file to AAC
          echo "# ${FILE_NAME} - Audio #${TRACK_ID} : Convertion to AAC (${TRACK_RATE}k)"
          fdkaac -o "${FILE_TMP_AAC}" -b ${TRACK_RATE}k "${FILE_TMP_WAV}" 

          # determine if current track is default audio
          [ ${TRACK_DEFAULT} = "TRUE" ] && ARR_PARAM_AUDIO=("${ARR_PARAM_AUDIO[@]}" "--default-track" "0:1") || ARR_PARAM_AUDIO=("${ARR_PARAM_AUDIO[@]}" "--default-track" "0:0")

          # gererate track options for current track
          ARR_PARAM_AUDIO=("${ARR_PARAM_AUDIO[@]}" "--sync" "0:${TRACK_DELAY}" "--language" "0:${TRACK_LANGUAGE}" "--track-name" "0:${TRACK_LANGUAGE} (${TRACK_CHANNEL} channels)" "${FILE_TMP_AAC}")

          # add current audio to the general track order list
          ARR_FILE=("${ARR_FILE[@]}" "${NEWTRACK_INDEX}:0")
          NEWTRACK_INDEX=$((NEWTRACK_INDEX+1))
        fi
      fi

      # if nightmode track is needed, generate AAC stereo night mode track
      if [ "${TRACK_NIGHTMODE}" = "TRUE" ]
      then
        # if not already done, extract audio track to MKA audio file
        echo "# ${FILE_NAME} - Audio #${TRACK_ID} : Extraction of ${TRACK_FORMAT} stream"
        [ -f "${FILE_TMP_MKA}" ] || mkvmerge -o "${FILE_TMP_MKA}" --no-video --audio-tracks ${TRACK_ID} --no-subtitles --no-attachments --no-global-tags --no-chapters --no-track-tags --no-buttons "${FILE_PATH}"

        # convert WAV file to stereo
        echo "# ${FILE_NAME} - Audio #${TRACK_ID} : Conversion to stereo WAV"
        avconv -y -i "${FILE_TMP_MKA}" -ac 2 "${FILE_TMP_WAV}"

        # apply night mode correction
        echo "# ${FILE_NAME} - Audio #${TRACK_ID} : Conversion to Midnight Mode"
        sox --temp $HOME "${FILE_TMP_WAV}" "${FILE_DRC_WAV}" compand 0.0,1 6:-70,-50,-20 -6 -90 0.1

        # normalize audio track
        echo "# ${FILE_NAME} - Audio #${TRACK_ID} : Normalization of Midnight Mode"
        sox --temp $HOME --norm "${FILE_DRC_WAV}" "${FILE_NRM_WAV}"

        # convert WAV file to AAC
        echo "# ${FILE_NAME} - Audio #${TRACK_ID} : Conversion of Midnight Mode to AAC (${RATE_DRC}k)"
        fdkaac -o "${FILE_DRC_AAC}" -b ${RATE_DRC}k "${FILE_NRM_WAV}" 

        # gererate track options for current track
        ARR_PARAM_AUDIO=("${ARR_PARAM_AUDIO[@]}" "--default-track" "0:0"  "--sync" "0:${TRACK_DELAY}" "--language" "0:${TRACK_LANGUAGE}" "--track-name" "0:${TRACK_LANGUAGE} Night Mode" "${FILE_DRC_AAC}")

        # add current audio to the general track order list
        ARR_FILE=("${ARR_FILE[@]}" "${NEWTRACK_INDEX}:0")
        NEWTRACK_INDEX=$((NEWTRACK_INDEX+1))
      fi

      # remove temporary files
      [ -f "${FILE_TMP_MKA}" ] && rm "${FILE_TMP_MKA}"
      [ -f "${FILE_TMP_WAV}" ] && rm "${FILE_TMP_WAV}"
      [ -f "${FILE_DRC_WAV}" ] && rm "${FILE_DRC_WAV}"
      [ -f "${FILE_NRM_WAV}" ] && rm "${FILE_NRM_WAV}"
    done

    # ---------------------------------------------------------------------
    #  generate audio track arrays used for final merge
    # ---------------------------------------------------------------------

    # if needed, generate list of AAC audio tracks
    LIST_AAC=$(echo "${ARR_AAC_ID[@]}" | sed 's/ /,/g')
    [ "$LIST_AAC" != "" ] && ARR_PARAM_AAC=("--audio-tracks" "${LIST_AAC}" "${ARR_PARAM_AAC[@]}") || ARR_PARAM_AAC=("--no-audio" )

    # generate list of ACC track index
    LIST_FILE=$(echo "${ARR_FILE[@]}" | sed 's/ /,/g')

    # ---------------------------------------------------------------------
    #  if video cover is present, include cover in final merge
    # ---------------------------------------------------------------------

    if [ -f "${FILE_COVER}" ]
    then
      echo "# ${FILE_NAME} - Addition of video cover"
      ARR_PARAM_COVER=("--attachment-description" "Movie cover" "--attachment-mime-type" "image/jpg" "--attachment-name" "cover.jpg" "--attach-file" "${FILE_COVER}") 
    fi

    # ---------------------------------------------------------------------
    #  final merge
    # ---------------------------------------------------------------------

    # generate final MKV including original file and transcoded tracks
    echo "# ${FILE_NAME} - Generation of final MKV"
    mv "${FILE_PATH}" "${FILE_ORG}"
    mkvmerge --title "${FILE_NAME}" --track-order "${LIST_FILE}" "${ARR_PARAM_COVER[@]}" --output "${FILE_MKV}" "${ARR_PARAM_AAC[@]}" --no-buttons --no-attachments "${FILE_ORG}" "${ARR_PARAM_AUDIO[@]}"

    # clean all temporary M4A files
    rm -f "${FILE_BASE}"-*.m4a
  fi

  # remove information file
  [ -f "${FILE_INFO}" ] && rm "${FILE_INFO}"
done

) | zenity --window-icon=video --width=500 --title="Conversion to MKV with AAC audio" --progress --pulsate --auto-close &

# get zenity process and child proces which is parent of all running tasks 
PID_ZENITY=${!}
PID_CHILD=$(pgrep -o -P $$)

# loop to check that progress dialog has not been cancelled
while [ "$PID_ZENITY" != "" ]
do
  # get PID of running processes for the children
  PID_TASKS=$(pgrep -d ' ' -P "${PID_CHILD}")

  # check if process is still running
  PID_ZENITY=$(ps h -o pid --pid ${PID_ZENITY} | xargs)

  # sleep for 2 second
  sleep 2
done

# if some running tasks are still there, kill them
[ "${PID_TASKS}" != "" ] && kill -9 ${PID_TASKS}

You can install and test the script from command line :

Terminal
# mkdir --parents $HOME/.config
# wget -O $HOME/.config/video-convert2mkvaac.conf https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/video-convert2mkvaac.conf
# sudo wget -O /usr/local/bin/video-convert2mkvaac https://raw.githubusercontent.com/NicolasBernaerts/ubuntu-scripts/master/video/video-convert2mkvaac
# sudo chmod +x /usr/local/bin/video-convert2mkvaac

You are now ready to test it :

Terminal
# video-convert2mkvaac yourvideofile.mp4

If everything runs fine, you should get the 2 selection dialog boxes and end up with a brand new MKV file side to your original video.

3. Desktop Integration

It is now time to fully integrate this MKV/AAC transcoding tool in your desktop environment.

3.1. Menu declaration

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

/usr/share/applications/video-convert2mkvaac.desktop
[Desktop Entry]
Version=1.0
Type=Application
Terminal=false
Exec=/usr/local/bin/video-convert2mkvaac
Name=Convert to MKV/AAC
Categories=GNOME;AudioVideo;AudioVideoEditing;
MimeType=video/*;
Icon=video

It should be avaiable from Application / Sound & Video menu after next login.

3.2. Nautilus integration

You can also integrate this tool straight from Nautilus file manager. You'll then be able to access it from a right click menu after selecting file(s).

First thing is to install nautilus-actions extensions, which is not installed by default under Ubuntu.

Terminal
# sudo apt-get install nautilus-actions

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

~/.local/share/file-manager/actions/video-convert2mkvaac-action.desktop
[Desktop Entry]
Type=Action
Icon=video
Name[C]=Convert to MKV with AAC audio
Name[en]=Convert to MKV with AAC audio
Name[en_US]=Convert to MKV with AAC audio
Name[fr_FR]=Conversion en fichier MKV avec audio AAC
Tooltip[C]=Conversion of any video file to a MKV container with AAC audio
Tooltip[en]=Conversion of any video file to a MKV container with AAC audio
Tooltip[en_US]=Conversion of any video file to a MKV container with AAC audio
Tooltip[fr_FR]=Outil de conversion d'un fichier video en fichier MKV avec audio au format AAC
Profiles=convert2mkvaac_video;

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

This will make the transcoding tool accessible from the right menu on any video file whose mimetypes is matching the one declared in the .desktop file.

You will then be able to start the transcoding of any video file from a simple right click in Nautilus.

ubuntu mkvaac menu rightclick

To declare this Nautilus action, just run these commands :

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

4. Complete installation procedure

If you want to install all needed tools and scripts in one go, you can run an all-in-one installation script available from my Github repository.

This script has been written and tested on Ubuntu 14.04 LTS. It will handle whatever installation and configuration described earlier in this article.

Terminal

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

After next login, you should be able to generate a MKV/AAC video file from any multi-tracks 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