Combine mp4 files by order based on number from filenames in Python
Question:
I try to merge lots of mp4
files from a directory test
into one output.mp4
using ffmpeg
in Python.
import os
path = '/Users/x/Documents/test'
for filename in os.listdir(path):
if filename.endswith(".mp4"):
print(filename)
Output:
4. 04-unix,minix,Linux.mp4
6. 05-Linux.mp4
7. 06-ls.mp4
5. 04-unix.mp4
9. 08-command.mp4
1. 01-intro.mp4
3. 03-os.mp4
8. 07-minux.mp4
2. 02-os.mp4
10. 09-help.mp4
I have tried with the solution below from the reference here: ffmpy concatenate multiple files with a file list
import os
import subprocess
import time
base_dir = "/path/to/the/files"
video_files = "video_list.txt"
output_file = "output.avi"
# where to seek the files
file_list = open(video_files, "w")
# remove prior output
try:
os.remove(output_file)
except OSError:
pass
# scan for the video files
start = time.time()
for root, dirs, files in os.walk(base_dir):
for video in files:
if video.endswith(".avi"):
file_list.write("file './%s'n" % video)
file_list.close()
# merge the video files
cmd = ["ffmpeg",
"-f",
"concat",
"-safe",
"0",
"-loglevel",
"quiet",
"-i",
"%s" % video_files,
"-c",
"copy",
"%s" % output_file
]
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
fout = p.stdin
fout.close()
p.wait()
print(p.returncode)
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd)
end = time.time()
print("Merging the files took", end - start, "seconds.")
I have merged them and get an output.mp4
but the files are not merged in order with the first number split by point (1, 2, 3, ...
): which I can get by filename.split(".")[0]
:
1. 01-intro.mp4
2. 02-os.mp4
3. 03-os.mp4
4. 04-unix,minix,Linux.mp4
5. 04-unix.mp4
6. 05-Linux.mp4
7. 06-ls.mp4
8. 07-minux.mp4
9. 08-command.mp4
10. 09-help.mp4
How can I merge them correctly and concisely in Python? Thanks.
Answers:
This solution works:
from moviepy.editor import *
import os
from natsort import natsorted
L = []
for root, dirs, files in os.walk("/path/to/the/files"):
#files.sort()
files = natsorted(files)
for file in files:
if os.path.splitext(file)[1] == '.mp4':
filePath = os.path.join(root, file)
video = VideoFileClip(filePath)
L.append(video)
final_clip = concatenate_videoclips(L)
final_clip.to_videofile("output.mp4", fps=24, remove_temp=False)
import glob
import os
def concatenate():
global stringa
stringa = "ffmpeg -i "concat:"
elenco_video = glob.glob("*.mp4")
elenco_file_temp = []
for f in elenco_video:
file = "temp" + str(elenco_video.index(f) + 1) + ".ts"
os.system("ffmpeg -i " + f + " -c copy -bsf:v h264_mp4toannexb -f mpegts " + file)
elenco_file_temp.append(file)
print(elenco_file_temp)
for f in elenco_file_temp:
stringa += f
if elenco_file_temp.index(f) != len(elenco_file_temp)-1:
stringa += "|"
else:
stringa += "" -c copy -bsf:a aac_adtstoasc output.mp4"
print(stringa)
os.system(stringa)
this will create a concatenated video file named output.mp4
in the working directory,,
code source
My videos got crossed up and blurred due to different frame sizes.. to avoid that you can use this. It was only a change to this line:
final_clip = concatenate_videoclips(L,method='compose')
which adds all the clips together despite the different frame sizes. Heres the full code:
from moviepy.editor import *
import os
from natsort import natsorted
def combine_videos_folder_to_one(folder_path):
L =[]
for root, dirs, files in os.walk(folder_path):
#files.sort()
files = natsorted(files)
for file in files:
if os.path.splitext(file)[1] == '.mp4':
filePath = os.path.join(root, file)
video = VideoFileClip(filePath)
L.append(video)
final_clip = concatenate_videoclips(L,method='compose')
final_clip.to_videofile("compilation_output.mp4", fps=60, remove_temp=False)
combine_videos_folder_to_one(folder_videos)
I try to merge lots of mp4
files from a directory test
into one output.mp4
using ffmpeg
in Python.
import os
path = '/Users/x/Documents/test'
for filename in os.listdir(path):
if filename.endswith(".mp4"):
print(filename)
Output:
4. 04-unix,minix,Linux.mp4
6. 05-Linux.mp4
7. 06-ls.mp4
5. 04-unix.mp4
9. 08-command.mp4
1. 01-intro.mp4
3. 03-os.mp4
8. 07-minux.mp4
2. 02-os.mp4
10. 09-help.mp4
I have tried with the solution below from the reference here: ffmpy concatenate multiple files with a file list
import os
import subprocess
import time
base_dir = "/path/to/the/files"
video_files = "video_list.txt"
output_file = "output.avi"
# where to seek the files
file_list = open(video_files, "w")
# remove prior output
try:
os.remove(output_file)
except OSError:
pass
# scan for the video files
start = time.time()
for root, dirs, files in os.walk(base_dir):
for video in files:
if video.endswith(".avi"):
file_list.write("file './%s'n" % video)
file_list.close()
# merge the video files
cmd = ["ffmpeg",
"-f",
"concat",
"-safe",
"0",
"-loglevel",
"quiet",
"-i",
"%s" % video_files,
"-c",
"copy",
"%s" % output_file
]
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
fout = p.stdin
fout.close()
p.wait()
print(p.returncode)
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, cmd)
end = time.time()
print("Merging the files took", end - start, "seconds.")
I have merged them and get an output.mp4
but the files are not merged in order with the first number split by point (1, 2, 3, ...
): which I can get by filename.split(".")[0]
:
1. 01-intro.mp4
2. 02-os.mp4
3. 03-os.mp4
4. 04-unix,minix,Linux.mp4
5. 04-unix.mp4
6. 05-Linux.mp4
7. 06-ls.mp4
8. 07-minux.mp4
9. 08-command.mp4
10. 09-help.mp4
How can I merge them correctly and concisely in Python? Thanks.
This solution works:
from moviepy.editor import *
import os
from natsort import natsorted
L = []
for root, dirs, files in os.walk("/path/to/the/files"):
#files.sort()
files = natsorted(files)
for file in files:
if os.path.splitext(file)[1] == '.mp4':
filePath = os.path.join(root, file)
video = VideoFileClip(filePath)
L.append(video)
final_clip = concatenate_videoclips(L)
final_clip.to_videofile("output.mp4", fps=24, remove_temp=False)
import glob
import os
def concatenate():
global stringa
stringa = "ffmpeg -i "concat:"
elenco_video = glob.glob("*.mp4")
elenco_file_temp = []
for f in elenco_video:
file = "temp" + str(elenco_video.index(f) + 1) + ".ts"
os.system("ffmpeg -i " + f + " -c copy -bsf:v h264_mp4toannexb -f mpegts " + file)
elenco_file_temp.append(file)
print(elenco_file_temp)
for f in elenco_file_temp:
stringa += f
if elenco_file_temp.index(f) != len(elenco_file_temp)-1:
stringa += "|"
else:
stringa += "" -c copy -bsf:a aac_adtstoasc output.mp4"
print(stringa)
os.system(stringa)
this will create a concatenated video file named output.mp4
in the working directory,,
code source
My videos got crossed up and blurred due to different frame sizes.. to avoid that you can use this. It was only a change to this line:
final_clip = concatenate_videoclips(L,method='compose')
which adds all the clips together despite the different frame sizes. Heres the full code:
from moviepy.editor import *
import os
from natsort import natsorted
def combine_videos_folder_to_one(folder_path):
L =[]
for root, dirs, files in os.walk(folder_path):
#files.sort()
files = natsorted(files)
for file in files:
if os.path.splitext(file)[1] == '.mp4':
filePath = os.path.join(root, file)
video = VideoFileClip(filePath)
L.append(video)
final_clip = concatenate_videoclips(L,method='compose')
final_clip.to_videofile("compilation_output.mp4", fps=60, remove_temp=False)
combine_videos_folder_to_one(folder_videos)