I\'m trying to concatenate two mp4 files using ffmpeg. I need this to be an automatic process hence why I chose ffmpeg. I\'m converting the two files into .ts files and th
A one-liner snippet that does not require an intermediate file:
ffmpeg -safe 0 -f concat -i <(find "$PWD" -name '*.mp4' -printf "file '%p'\n" | sort) -c copy output.mp4
Here, the <()
syntax actually creates a temporary file "in the background" so to say
After various tries below script worked for me on windows 10 powershell.
$files=Get-ChildItem -path e:\ -Filter *.mp4
$files| ForEach-Object {"file '$($_.FullName)'"}| Out-File -FilePath e:\temp.txt -Encoding ASCII
if (-not (test-path "e:\ffmpeg\bin\ffmpeg.exe")) {throw "e:\ffmpeg\bin\ffmpeg.exe needed"}
E:\ffmpeg\bin\ffmpeg.exe -safe 0 -f concat -i "e:\temp.txt" -c copy -bsf:v hevc_mp4toannexb -an e:\joined.mp4
# Conversion Cleanup
Remove-Item e:\temp.txt
Here first two lines create a text file temp.txt which has following content
file 'e:\first.mp4'
file 'e:\second.mp4'
3rd, 4th lines checks if ffmpeg is available at path and create the "joined.mp4"
The key differences from other answers are as below
usage of -bsf:v hevc_mp4toannexb -an
for my mp4 file above worked, you may need to use other alternatives like below depending on your video encoding.
h264_mp4toannexb
All such possible Bitstream filters can be found at https://ffmpeg.org/ffmpeg-bitstream-filters.html
Here's a fast (takes less than 1 minute) and lossless way to do this without needing intermediate files:
ls Movie_Part_1.mp4 Movie_Part_2.mp4 | \
perl -ne 'print "file $_"' | \
ffmpeg -f concat -i - -c copy Movie_Joined.mp4
The "ls" contains the files to join The "perl" creates the concatenation file on-the-fly into a pipe The "-i -" part tells ffmpeg to read from the pipe
(note - my files had no spaces or weird stuff in them - you'll need appropriate shell-escaping if you want to do this idea with "hard" files).
ffmpeg
and not usingOne-liner solution using ls
ls video1.mp4 video2.mp4 | while read line; do echo file \'$line\'; done | ffmpeg -protocol_whitelist file,pipe -f concat -i - -c copy output.mp4
Function which takes 0 or 2+ arguments
#######################################
# Merge mp4 files into one output mp4 file
# usage:
# mergemp4 #merges all mp4 in current directory
# mergemp4 video1.mp4 video2.mp4
# mergemp4 video1.mp4 video2.mp4 [ video3.mp4 ...] output.mp4
#######################################
function mergemp4() {
if [ $# = 1 ]; then return; fi
outputfile="output.mp4"
#if no arguments we take all mp4 in current directory as array
if [ $# = 0 ]; then inputfiles=($(ls -1v *.mp4)); fi
if [ $# = 2 ]; then inputfiles=($1 $2); fi
if [ $# -ge 3 ]; then
outputfile=${@: -1} # Get the last argument
inputfiles=(${@:1:$# - 1}) # Get all arguments besides last one as array
fi
# -y: automatically overwrite output file if exists
# -loglevel quiet: disable ffmpeg logs
ffmpeg -y \
-loglevel quiet \
-f concat \
-safe 0 \
-i <(for f in $inputfiles; do echo "file '$PWD/$f'"; done) \
-c copy $outputfile
if test -f "$outputfile"; then echo "$outputfile created"; fi
}
Note: had tried some solutions in this thread and none satisfied me