Simple script to join files using ffmpeg

A simple script to join files using ffmpeg. This script works in Linux only.

Save the following code as a script file. For example, save as joinvideos.sh and set the executable permission with chmod 755 joinvideos.sh. Then copy all videos that need to be joined in a single folder containing the script. The script will join any video files it finds in the folder. The script will also join the video files in the alphabetical order of their names. So it is important to rename the files as f1.mp4, f2.mp4, f3.mp4 if the original filenames have no naming order.

#!/bin/bash
# joinvideos.sh v1.5 by Saugata
# join multiple video files with ffmpeg 

# remove temp files if they exist from interrupted past run
if ls temp-*.mp4 1> /dev/null 2>&1; then
  echo "Removing older temp*.mp4 files"
  rm temp-*.mp4
fi

# make a list of all mp4 files in the diretory 
# except the output.mp4 if it exists
listofvidfiles=`ls -1 | grep mp4 | grep -v "output"`

for f in $listofvidfiles;
do
  # check for location of Video stream
  # if Video is at Stream #0:1 then swap to Stream #0:0
  # save file as temp file
  vidstreamno=`ffprobe $f 2>&1 | grep Video | cut -d":" -f2 | cut -d"(" -f1`
  if [ "$vidstreamno" -eq "1" ]; then
    ffmpeg -i $f -map 0:1 -map 0:0 -c copy temp-$f
  else
    cp $f temp-$f
  fi
  # if Video is at Stream #0:0 then copy it to a temp file
  echo $f: "Video stream at" $vidstreamno
done

# create a text files from list of temp-*.mp4 for ffmpeg input
ls -1 *.mp4 | grep mp4 | grep temp | sed "s/^/file '/" | sed "s/$/\'/" > vidfilelist.txt 
echo "-----------------------------"
echo "Joining files ..............."
cat vidfilelist.txt 
echo "-----------------------------"

# use ffmpeg to join mp4 files
ffmpeg -f concat -safe 0 -i vidfilelist.txt -c copy output.mp4

# clean temp files before exit
if ls temp-*.mp4 1> /dev/null 2>&1; then
  echo "Removing temp*.mp4 files"
  rm temp-*.mp4
fi

 

Getting error: Non-monotonous DTS while concatenating video files in ffmpeg

ffmpeg is a versatile tool which can concat multiple videos into a single video with minimal processing load. ffmpeg takes a text file with a list of video files to be joined in the order they are to be concatenated. A sample command will look like this.

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

This command can be used universally as long as mylist.txt file contains the correct list of video files that are to be joined. The text file might look like this.

# this is a comment
file 'f1.mp4'
file 'f2.mp4'

I was joining pieces of lecture videos recently using ffmpeg and it was working perfectly till it broke. I started getting the error “Non-monotonous DTS in output stream”.

[mp4 @ 0x559118faf340] Non-monotonous DTS in output stream 0:1; previous: 10392576, current: 9748800; changing to 10392577. This may result in incorrect timestamps in the output file.

The issue seemed to be due to the video file itself. The online forums discussed something about the timestamp which didn’t make sense. I checked the encoding and bitrates and all seemed to be in order except the video and the audios steams are switched in the second video. While f1.mp4 contains the audio stream at Steam #0:0, f2.mp4 contains the audio stream at Steam #0:1.

Screenshot from 2020-05-07 00-44-29

To correct this we used the map function of ffmpeg to swap the audio and the video streams.

$ ffmpeg -i f2.mp4 -map 0:1 -map 0:0 -c copy  new.mp4

 

And the ffmpeg -f concat started working again!!

References:
[1] https://trac.ffmpeg.org/wiki/Map