Ubuntu – How to convert all video files in nested folders? (batch conversion)

video conversion

I have lots of large video files of my kids (.MTS format). Now I would like to convert them into divx / xvid to save hdd space and also have the ability to watch on my TV set.

Video files are stored in nested folders on my hdd (based on shooting times or special events). So, keeping the existing folder structure I would like to convert all the videos (which may take some days I believe) automatically.

I will appreciate if you can guide me how to achieve it?

Best Answer

You can use ffmpeg to convert video formats. If it isn't installed yet, get it using:

sudo apt install ffmpeg

I successfully tried the following command for converting a sample video to an AVI-based DivX 5.0 format:

ffmpeg -i sample.mp4 -f avi -vtag DX50 sample.divx

First you specify the input video file as e.g. -i Videos/sample.mts, then we say we want the output format to be AVI with an DivX 5.0 tag using -f avi -vtag: DX50. The last argument is the output file to generate, here Videos/sample.divx.

I recommend you to try with one small video first and verify that everything worked as expected and both the format is recognized by your player as well as the video quality and file size is okay. You can tweak the latter with an additional argument -q:v N, where N is a number and lower numbers mean higher quality and file size. Good values are probably in the range 2-8, maybe try 5:

ffmpeg -i sample.mp4 -f avi -vtag DX50 -q:v 5 sample.divx

Then once the test was successful and both format and quality are okay, you can batch-convert all your .mts video files inside a specific source directory recursively with a Bash script like this:

#!/bin/bash

# Change the directories and quality level (lower=better) below accordingly:
inputfolder="/path/to/somewhere"
outputfolder="/path/to/elsewhere"
videoquality=5

shopt -s globstar nocaseglob nocasematch  # enable ** and globs case-insensitivity

for inputfile in "$inputfolder"/**/*.mts ; do
    outputfile="$outputfolder/$(basename "${inputfile%.mts}").divx"
    ffmpeg -i "$inputfile" -f avi -vtag DX50 -q:v "$videoquality" "$outputfile"
done

Or if you want the output files in the same directory as the input, here's a shorter version:

#!/bin/bash

# Change the directory and quality level (lower=better) below accordingly:
folder="/path/to/somewhere"
videoquality=5

shopt -s globstar nocaseglob nocasematch  # enable ** and globs case-insensitivity

for inputfile in "$folder"/**/*.mts ; do
    ffmpeg -i "$inputfile" -f avi -vtag DX50 -q:v "$videoquality" "${inputfile%.mts}.divx"
done