Concatenate and reduce mp4 size with ffmpeg?

Might be kindof a hack, but this seem to automatically concat all the .mp4s in the current folder into one. It uses the foldername (stripped of whitespaces) for the output name. Might have numerous flaws, so use at own risk. Its just a mix and match of different snippets from stackoverflow.

Concat w/o re-encode:

for f in ./*.mp4; do echo "file '$f'" >> l.txt; done; ffmpeg -f concat -safe 0 -i l.txt -c copy $(printf '%s\n' "${PWD##*/}" | tr -d '[:space:]').mp4; rm l.txt

Re-encode to lower file-size:

ffmpeg -i input.mp4 -vcodec libx265 -crf 20 output.mp4


This kind of quoting may be questionable. However it is merely my notes. Please take any discussion/questions/credit et. back to the original posts/sites.


How can I reduce a video’s size with ffmpeg?

Calculate the bitrate you need by dividing 1 GB by the video length in seconds. So, for a video of length 16:40 (1000 seconds), use a bitrate of 1000000 bytes/sec:

ffmpeg -i input.mp4 -b 1000000 output.mp4

Additional options that might be worth considering is setting the Constant Rate Factor, which lowers the average bit rate, but retains better quality. Vary the CRF between around 18 and 24 — the lower, the higher the bitrate.

ffmpeg -i input.mp4 -vcodec libx265 -crf 20 output.mp4

Vary the codec as needed – libx264 may be available if libx265 is not, at the cost of a slightly larger resultant file size.

Generate filelist for all files in current folder for use with ffmpeg concat:

# with a bash for loop
for f in ./*.mp4; do echo "file '$f'" >> mylist.txt; done
# or with printf
printf "file '%s'\n" ./*.mp4 > mylist.txt

Concat demuxer (for no-re-encode mp4)

$ cat mylist.txt
file '/path/to/file1'
file '/path/to/file2'
file '/path/to/file3'

$ ffmpeg -f concat -safe 0 -i mylist.txt -c copy output.mp4

Ignore unsafe filenames:

Based on this:

ffmpeg -v info -f concat -i <(find STREAM -name '*' -printf "file '$PWD/%p'\n") -deinterlace -r 25 -s hd720 -c:v libx264 -crf 23 -acodec copy -strict -2 ~/tmp/Videos/20151222.mp4 

"Add -safe 0 before -i".

Get current directory name (without full path) in a Bash script

result=${PWD##*/}          # to assign to a variable

printf '%s\n' "${PWD##*/}" # to print to stdout
                           # ...more robust than echo for unusual names
                           #    (consider a directory named -e or -n)

printf '%q\n' "${PWD##*/}" # to print to stdout, quoted for use as shell input
                           # ...useful to make hidden characters readable.
Parameter expansion:

3.5.4 Command Substitution

Command substitution allows the output of a command to replace the command itself. Command substitution occurs when a command is enclosed as follows:



Bash performs the expansion by executing command in a subshell environment and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting. The command substitution $(cat file) can be replaced by the equivalent but faster $(< file).

How to remove all whitespace (denoted by [:space:] in tr):

FOO=' test test test '
FOO_NO_WHITESPACE="$(echo -e "${FOO}" | tr -d '[:space:]')"
# > FOO_NO_WHITESPACE='testtesttest'
# > length(FOO_NO_WHITESPACE)==12