I'm trying to make this application that will let you merge video clips together, however, when I try to merge two clips, I get this error: TypeError: 'VideoFileClip' object is not iterable
. moreover, when I want to merge more than 2 clips, let's say 3 clips, I get this error:
TypeError: 'VideoFileClip' object is not subscriptable
. Any help will be appreciated.
Full error, when 2 video clips given:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Totenkopf\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "D:/Python Projects/Windows/VideoMerger/main.py", line 80, in merge_vid
final_clip = concatenate_videoclips(clip1, clip2)
File "D:\Python Projects\Windows\VideoMerger\venv\lib\site-packages\moviepy\video\compositing\concatenate.py", line 71, in concatenate_videoclips
tt = np.cumsum([0] [c.duration for c in clips])
TypeError: 'VideoFileClip' object is not iterable
Full error when more than 2 clips given:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Totenkopf\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "D:/Python Projects/Windows/VideoMerger/main.py", line 87, in merge_vid
final_clip = concatenate_videoclips(clip1, clip2, clip3)
File "D:\Python Projects\Windows\VideoMerger\venv\lib\site-packages\moviepy\video\compositing\concatenate.py", line 67, in concatenate_videoclips
l = [[v, transition] for v in clips[:-1]]
TypeError: 'VideoFileClip' object is not subscriptable
Code:
def open_location():
global filename_splitted
filename = askopenfilename()
filename_ext = os.path.splitext(filename)
filename_splitted = str(filename_ext).split('/')[4].split(".")[0].split(',')[0].split("'")[0]
filename_ext_split = filename_ext[1][1:]
if len(filename) > 1 and filename_ext_split == "mp4":
path_url.config(text=filename_splitted, fg="green")
else:
messagebox.showwarning(title="oops", message="No video given!")
path_url.config(text="Please specify a file (mp4)!", fg="red")
return filename_splitted
def merge_vid():
number_of_videos = box.get()
if number_of_videos <= "1":
messagebox.showwarning(title="Warning", message="Please specify how many videos you want to merge.")
elif number_of_videos == "2":
clip1 = VideoFileClip(f"{open_location()}.mp4")
clip2 = VideoFileClip(f"{open_location()}.mp4")
final_clip = concatenate_videoclips(clip1, clip2)
final_clip.write_videofile('Final.mp4', codec="libx264")
elif number_of_videos == "3":
clip1 = VideoFileClip(f"{open_location()}.mp4")
clip2 = VideoFileClip(f"{open_location()}.mp4")
clip3 = VideoFileClip(f"{open_location()}.mp4")
final_clip = concatenate_videoclips(clip1, clip2, clip3)
final_clip.write_videofile('Final.mp4', codec="libx264")
elif number_of_videos == "4":
clip1 = VideoFileClip(f"{open_location()}.mp4")
clip2 = VideoFileClip(f"{open_location()}.mp4")
clip3 = VideoFileClip(f"{open_location()}.mp4")
clip4 = VideoFileClip(f"{open_location()}.mp4")
final_clip = concatenate_videoclips(clip1, clip2, clip3, clip4)
final_clip.write_videofile('Final.mp4', codec="libx264")
Here's the entire code in case anyone want to try it:
import tkinter
from moviepy.editor import *
from tkinter import *
from tkinter import messagebox
from tkinter import ttk
from tkinter import filedialog
import threading
import requests
import os
from tkinter.filedialog import askopenfilename
# import subprocess
# Converting video file types.
# subprocess.call("ffmpeg -i Z1.mov -q:v 0 Z1mp4.mp4", shell=True)
# subprocess.call("ffmpeg -i Z2.mov -q:v 0 Z2mp4.mp4", shell=True)
# subprocess.call("ffmpeg -i Z2.mov -q:v 0 Z3mp4.mp4", shell=True)
def prog_bar():
progressbar = Tk()
progressbar.geometry("555x33 600 100")
progressbar.title("Downloading ffmpeg, please wait...")
pb = ttk.Progressbar(progressbar, orient='horizontal', mode='determinate')
pb.pack(expand=True, fill=tkinter.BOTH, side=tkinter.TOP)
pb.start(11)
progressbar.after(60000, message2)
progressbar.after(90000, progressbar.destroy)
progressbar.mainloop()
def message2():
messagebox.showinfo(title="Download Completed", message="Download completed. Please restart the app.")
def download_ffmpeg():
r = requests.get("https://www.dropbox.com/s/ur8miwz54us8ruc/ffmpeg.exe?dl=1", allow_redirects=True)
open('C:/ffmpeg.exe', 'wb').write(r.content)
if os.path.exists("C:/ffmpeg.exe"):
os.environ["IMAGEIO_FFMPEG_EXE"] = r"C:\ffmpeg.exe"
else:
# threading.Thread(target=message1).start()
threading.Thread(target=prog_bar).start()
threading.Thread(target=download_ffmpeg).start()
start_time = threading.Timer(33, message2)
# start_time.start()
# os.environ["IMAGEIO_FFMPEG_EXE"] = rf"{directory}\ffmpeg"
os.environ["IMAGEIO_FFMPEG_EXE"] = r"C:\ffmpeg.exe"
def space():
space = Label(text="", bg="black")
space.pack()
def open_location():
global filename_splitted
filename = askopenfilename()
filename_ext = os.path.splitext(filename)
filename_splitted = str(filename_ext).split('/')[4].split(".")[0].split(',')[0].split("'")[0]
filename_ext_split = filename_ext[1][1:]
if len(filename) > 1 and filename_ext_split == "mp4":
path_url.config(text=filename_splitted, fg="green")
else:
messagebox.showwarning(title="oops", message="No video given!")
path_url.config(text="Please specify a file (mp4)!", fg="red")
return filename_splitted
def merge_vid():
number_of_videos = box.get()
if number_of_videos <= "1":
messagebox.showwarning(title="Warning", message="Please specify how many videos you want to merge.")
elif number_of_videos == "2":
clip1 = VideoFileClip(f"{open_location()}.mp4")
clip2 = VideoFileClip(f"{open_location()}.mp4")
final_clip = concatenate_videoclips(clip1, clip2)
final_clip.write_videofile('Final.mp4', codec="libx264")
elif number_of_videos == "3":
clip1 = VideoFileClip(f"{open_location()}.mp4")
clip2 = VideoFileClip(f"{open_location()}.mp4")
clip3 = VideoFileClip(f"{open_location()}.mp4")
final_clip = concatenate_videoclips(clip1, clip2, clip3)
final_clip.write_videofile('Final.mp4', codec="libx264")
elif number_of_videos == "4":
clip1 = VideoFileClip(f"{open_location()}.mp4")
clip2 = VideoFileClip(f"{open_location()}.mp4")
clip3 = VideoFileClip(f"{open_location()}.mp4")
clip4 = VideoFileClip(f"{open_location()}.mp4")
final_clip = concatenate_videoclips(clip1, clip2, clip3, clip4)
final_clip.write_videofile('Final.mp4', codec="libx264")
# def start_merge():
# merge_vid()
def put_music():
# audio = AudioFileClip("Music.mp3")
# video1 = VideoFileClip("Final.mp4")
# final = video1.set_audio(audio)
# final.write_videofile("output.mp4")
pass
root = Tk()
space()
space()
# root.iconbitmap("yt.ico")
root.title("Video Editor")
root.geometry("350x350")
root.columnconfigure(0, weight=1)
root.config(bg="black")
# space()
# path_btn = Button(root, width=11, height=2, bg="#CC1B25", fg="white", text="Select Video", command=open_location)
# path_btn.pack()
space()
space()
space()
label = Label(root, text="How many videos do you want to merge:", bg="black", fg="white", font=("jost", 9, "bold"))
label.pack()
EntryVar = StringVar()
box = Entry(root, width=7, textvariable=EntryVar)
box.pack()
space()
merge_btn = Button(root, width=27, height=3, bg="green", fg="white", text="Choose and Merge Videos", command=merge_vid)
merge_btn.pack()
space()
space()
# start_merge_btn = Button(root, width=27, height=3, bg="green", fg="white", text="Start Merge", command=start_merge)
# start_merge_btn.pack()
path_url = Label(root, text="", fg="red", bg="black", font=("jost", 9, "bold"))
path_url.pack()
root.mainloop()
CodePudding user response:
Please read the moviepy docs for function concatenate_videoclips(clips, ..)
, especially about positional parameter clips
:
clips
A list of video clips which must all have theirduration
attributes set.
Following this, you should pass a list like [clip1, clip2]
when invoking this method like this:
clip1 = VideoFileClip(f"{open_location()}.mp4")
clip2 = VideoFileClip(f"{open_location()}.mp4")
final_clip = concatenate_videoclips( [clip1, clip2] ) # both clips inside a list
See also the video concatenation example in the guide Mixing clips — MoviePy 1.0.2 documentation.