使用 moviepy 进行多处理
multiprocessing with moviepy
最近我制作了一个脚本,需要一个 5 分钟的视频剪辑并剪切 5 个视频,每个视频 1 分钟,效果很好,但是对于像我这样的电脑来说它花费的时间太长了,而且我的电脑部分性能非常好:
Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz, 2904 Mhz, 8 Core(s), 16
Logical Processor(s)
Installed Physical Memory (RAM) 16.0 GB
所以我搜索了 moviepy 的文档“threads”,我在“write_videofile”函数中找到了一些东西,我可以设置我的线程来加速,我试过了,但它没有用,我的意思是它起作用了,但它唯一的改变可能是更多 2 或 3 it/s.
我还找到了多线程示例代码,但它似乎无法正常工作,因为 moviepy.multithreading 不存在于 moviepy 库中,请帮助我加快渲染速度,
谢谢
这是我找到的代码:
from moviepy.multithreading import multithread_write_videofile
def concat_clips():
files = [
"myclip1.mp4",
"myclip2.mp4",
"myclip3.mp4",
"myclip4.mp4",
]
multithread_write_videofile("output.mp4", get_final_clip, {"files": files})
def get_final_clip(files):
clips = [VideoFileClip(file) for file in files]
final = concatenate_videoclips(clips, method="compose")
return final
这是我的代码:
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
from numpy import array, true_divide
import cv2
import time
# ffmpeg_extract_subclip("full.mp4", start_seconds, end_seconds, targetname="cut.mp4")
def duration_clip(filename):
clip = VideoFileClip(filename)
duration = clip.duration
return duration
current_time = time.strftime("%Y_%m_%d_%H_%M_%S")
def main():
global duration
start = 0
cut_name_num = 1
end_seconds = start + 60
video_duration = duration_clip("video.mp4")
txt = input("Enter Your text please: ") [::-1]
txt_part = 1
while start < int(video_duration):
final_text = f"{str(txt_part)} {txt}"
try:
try:
os.makedirs(f"result_{str(current_time)}/result_edit")
except FileExistsError:
pass
ffmpeg_extract_subclip("video.mp4", start, end_seconds, targetname=f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip = VideoFileClip(f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip = clip.subclip(0, 60)
clip = clip.volumex(2)
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize = 50, color = 'white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
video = CompositeVideoClip([clip, txt_clip])
clip.write_videofile(f"result_{str(current_time)}/result_edit/cut_{str(cut_name_num)}.mp4")
except:
try:
os.makedirs(f"result_{str(current_time)}/result_edit")
except FileExistsError:
pass
ffmpeg_extract_subclip("video.mp4", start, video_duration, targetname=f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip_duration = duration_clip(f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip = VideoFileClip(f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip = clip.subclip(0, clip_duration)
clip = clip.volumex(2)
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize = 50, color = 'white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
video = CompositeVideoClip([clip, txt_clip])
clip.write_videofile(f"result_{str(current_time)}/result_edit/cut_{str(cut_name_num)}.mp4")
start += 60
cut_name_num += 1
end_seconds = start + 60
txt_part += 1
if __name__ == "__main__":
main()
使用进程,我只减少了 15-20 秒的时间,因为 ffmpeg
即使在单个进程中也几乎使用了全部 CPU 电源,而我的计算机没有电源 运行其他进程更快。
首先我减少了代码以使其更短。
try
和 except
中的代码具有相似的元素,因此我将它们移到 try/except
之外。
接下来我用了
if end > video_duration:
end = video_duration
而且我根本不需要 try/except
。
使用 os.makedirs(..., exist_ok=True)
我不需要 运行 它在 try/except
与此同时,我使用
将时间缩短了 20 秒
clip = VideoFileClip(filename).subclip(start, end)
而不是
temp_filename = f"{base_folder}/cut_{number}.mp4"
fmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
clip = VideoFileClip(temp_filename)
这样我就不会在磁盘上写入子剪辑,也不必再次从磁盘读取它。
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
import time
def main():
text = input("Enter Your text please: ") [::-1]
#text = 'Hello World'
base_folder = time.strftime("result_%Y_%m_%d_%H_%M_%S")
os.makedirs(f"{base_folder}/result_edit", exist_ok=True)
filename = "video.mp4"
#filename = "BigBuckBunny.mp4"
video_duration = VideoFileClip(filename).duration
number = 0 # instead of `cut_name_num` and `txt_part` because both had the same value
time_start = time.time()
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
clip_duration = end - start
print(f'[DEBUG] number: {number:2} | start: {start:6.2f} | end: {end:6.2f} | duration: {clip_duration:.2f}')
final_text = f"{number} {text}"
temp_filename = f"{base_folder}/cut_{number}.mp4"
final_filename = f"{base_folder}/result_edit/cut_{number}.mp4"
#ffmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
#clip = VideoFileClip(temp_filename)
clip = VideoFileClip(filename).subclip(start, end)
clip = clip.volumex(2)
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize=50, color='white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
video = CompositeVideoClip([clip, txt_clip])
video.write_videofile(final_filename)
# - after loop -
# because I use `number += 1` before loop so now `number` has number of subclips
print('number of subclips:', number)
time_end = time.time()
diff = time_end - time_start
print(f'time: {diff:.2f}s ({diff//60:02.0f}:{diff%60:02.2f})')
if __name__ == "__main__":
main()
接下来我将代码移动到带参数的函数中 my_process(filename, text, start, end, number, base_folder)
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
import time
def my_process(filename, text, start, end, number, base_folder):
clip_duration = end - start
print(f'[DEBUG] number: {number:2} | start: {start:6.2f} | end: {end:6.2f} | duration: {clip_duration:.2f}')
final_text = f"{number} {text}"
temp_filename = f"{base_folder}/cut_{number}.mp4"
final_filename = f"{base_folder}/result_edit/cut_{number}.mp4"
#print('[DEBUG] ffmpeg_extract_subclip')
#ffmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
#print('[DEBUG] VideoClip')
#clip = VideoFileClip(temp_filename)
clip = VideoFileClip(filename).subclip(start, end)
clip = clip.volumex(2)
#print('[DEBUG] TextClip')
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize=50, color='white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
#print('[DEBUG] CompositeVideoClip')
video = CompositeVideoClip([clip, txt_clip])
#print('[DEBUG] CompositeVideoClip write')
video.write_videofile(final_filename)
#print('[DEBUG] CompositeVideoClip end')
def main():
text = input("Enter Your text please: ") [::-1]
#text = 'Hello World'
base_folder = time.strftime("result_%Y_%m_%d_%H_%M_%S")
os.makedirs(f"{base_folder}/result_edit", exist_ok=True)
filename = "video.mp4"
#filename = "BigBuckBunny.mp4"
video_duration = VideoFileClip(filename).duration
number = 0 # instead of `cut_name_num` and `txt_part` because both had the same value
time_start = time.time()
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
my_process(filename, text, start, end, number, base_folder)
# - after loop -
# because I use `number += 1` before loop so now `number` has number of subclips
print('number of subclips:', number)
time_end = time.time()
diff = time_end - time_start
print(f'time: {diff:.2f}s ({diff//60:02.0f}:{diff%60:02.2f})')
if __name__ == "__main__":
main()
现在我可以 运行 使用标准模块 multiprocessing
在单独的进程中运行
(或标准模块 threading, concurrent.futures or external modules Joblib, Ray,等等)。
它启动单进程
# it has to use named arguments`target=`, `args=`
p = multiprocessing.Process(target=my_process, args=(filename, text, start, end, number, base_folder))
p.start() # start it
但如果我在循环中使用它,那么我将同时启动许多进程。
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
import time
import multiprocessing
def my_process(filename, text, start, end, number, base_folder):
clip_duration = end - start
print(f'[DEBUG] number: {number:2} | start: {start:6.2f} | end: {end:6.2f} | duration: {clip_duration:.2f}')
final_text = f"{number} {text}"
temp_filename = f"{base_folder}/cut_{number}.mp4"
final_filename = f"{base_folder}/result_edit/cut_{number}.mp4"
#print('[DEBUG] ffmpeg_extract_subclip')
#ffmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
#print('[DEBUG] VideoClip')
#clip = VideoFileClip(temp_filename)
clip = VideoFileClip(filename).subclip(start, end)
clip = clip.volumex(2)
#print('[DEBUG] TextClip')
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize=50, color='white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
#print('[DEBUG] CompositeVideoClip')
video = CompositeVideoClip([clip, txt_clip])
#print('[DEBUG] CompositeVideoClip write')
video.write_videofile(final_filename)
#print('[DEBUG] CompositeVideoClip end')
def main():
text = input("Enter Your text please: ") [::-1]
#text = 'Hello World'
base_folder = time.strftime("result_%Y_%m_%d_%H_%M_%S")
os.makedirs(f"{base_folder}/result_edit", exist_ok=True)
filename = "video.mp4"
#filename = "BigBuckBunny.mp4"
video_duration = VideoFileClip(filename).duration
number = 0 # instead of `cut_name_num` and `txt_part` because both had the same value
time_start = time.time()
all_processes = []
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
print("add process:", number)
p = multiprocessing.Process(target=my_process, args=(filename, text, start, end, number, base_folder)) # it has to use `target=`, `args=`
p.start() # start it
all_processes.append(p) # keep it to use `join()`
# - after loop -
for p in all_processes:
p.join() # wait for the end of process
# because I use `number += 1` before loop so now `number` has number of subclips
print('number of subclips:', number)
time_end = time.time()
diff = time_end - time_start
print(f'time: {diff:.2f}s ({diff//60:02.0f}:{diff%60:02.2f})')
if __name__ == "__main__":
main()
11 个子剪辑的旧版本启动 11 个进程。使用 Pool(4)
您可以将所有进程放入池中,它会同时 运行 4 个进程。当一个进程完成任务时,它将使用新参数启动下一个进程。
这次我使用循环为所有进程创建带有参数的列表
args_for_all_processes = []
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
print("add process:", number)
args_for_all_processes.append( (filename, text, start, end, number, base_folder) )
我将此列表与 Pool
一起使用,它会完成剩下的工作。
# I have 4 CPU so I use Pool(4) - but without value it should automatically use `os.cpu_count()`
with multiprocessing.Pool(4) as pool:
results = pool.starmap(my_process, args_for_all_processes)
#print(results)
Pool
可能会以不同的顺序启动进程,但如果他们使用 return
发送一些结果,那么 Pool
将以正确的顺序给出结果。
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
import time
import multiprocessing
def my_process(filename, text, start, end, number, base_folder):
clip_duration = end - start
print(f'[DEBUG] number: {number:2} | start: {start:6.2f} | end: {end:6.2f} | duration: {clip_duration:.2f}')
final_text = f"{number} {text}"
temp_filename = f"{base_folder}/cut_{number}.mp4"
final_filename = f"{base_folder}/result_edit/cut_{number}.mp4"
#print('[DEBUG] ffmpeg_extract_subclip')
#ffmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
#print('[DEBUG] VideoClip')
#clip = VideoFileClip(temp_filename)
clip = VideoFileClip(filename).subclip(start, end)
clip = clip.volumex(2)
#print('[DEBUG] TextClip')
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize=50, color='white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
#print('[DEBUG] CompositeVideoClip')
video = CompositeVideoClip([clip, txt_clip])
#print('[DEBUG] CompositeVideoClip write')
video.write_videofile(final_filename)
#print('[DEBUG] CompositeVideoClip end')
# return "OK" # you can use `return` to send result/information to main process.
def main():
text = input("Enter Your text please: ") [::-1]
#text = 'Hello World'
base_folder = time.strftime("result_%Y_%m_%d_%H_%M_%S")
os.makedirs(f"{base_folder}/result_edit", exist_ok=True)
filename = "video.mp4"
#filename = "BigBuckBunny.mp4"
video_duration = VideoFileClip(filename).duration
number = 0 # instead of `cut_name_num` and `txt_part` because both had the same value
time_start = time.time()
# first create list with arguments for all processes
args_for_all_processes = []
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
print("add process:", number)
args_for_all_processes.append( (filename, text, start, end, number, base_folder) )
# - after loop -
# next put all processes to pool
with multiprocessing.Pool(4) as pool: # I have 4 CPU so I use Pool(4) - but it should use `os.cpu_count()` in `Pool()
results = pool.starmap(my_process, args_for_all_processes)
#print(results)
# - after loop -
# because I use `number += 1` before loop so now `number` has number of subclips
print('number of subclips:', number)
time_end = time.time()
diff = time_end - time_start
print(f'time: {diff:.2f}s ({diff//60:02.0f}:{diff%60:02.2f})')
if __name__ == "__main__":
main()
最近我制作了一个脚本,需要一个 5 分钟的视频剪辑并剪切 5 个视频,每个视频 1 分钟,效果很好,但是对于像我这样的电脑来说它花费的时间太长了,而且我的电脑部分性能非常好:
Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz, 2904 Mhz, 8 Core(s), 16 Logical Processor(s)
Installed Physical Memory (RAM) 16.0 GB
所以我搜索了 moviepy 的文档“threads”,我在“write_videofile”函数中找到了一些东西,我可以设置我的线程来加速,我试过了,但它没有用,我的意思是它起作用了,但它唯一的改变可能是更多 2 或 3 it/s.
我还找到了多线程示例代码,但它似乎无法正常工作,因为 moviepy.multithreading 不存在于 moviepy 库中,请帮助我加快渲染速度, 谢谢
这是我找到的代码:
from moviepy.multithreading import multithread_write_videofile
def concat_clips():
files = [
"myclip1.mp4",
"myclip2.mp4",
"myclip3.mp4",
"myclip4.mp4",
]
multithread_write_videofile("output.mp4", get_final_clip, {"files": files})
def get_final_clip(files):
clips = [VideoFileClip(file) for file in files]
final = concatenate_videoclips(clips, method="compose")
return final
这是我的代码:
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
from numpy import array, true_divide
import cv2
import time
# ffmpeg_extract_subclip("full.mp4", start_seconds, end_seconds, targetname="cut.mp4")
def duration_clip(filename):
clip = VideoFileClip(filename)
duration = clip.duration
return duration
current_time = time.strftime("%Y_%m_%d_%H_%M_%S")
def main():
global duration
start = 0
cut_name_num = 1
end_seconds = start + 60
video_duration = duration_clip("video.mp4")
txt = input("Enter Your text please: ") [::-1]
txt_part = 1
while start < int(video_duration):
final_text = f"{str(txt_part)} {txt}"
try:
try:
os.makedirs(f"result_{str(current_time)}/result_edit")
except FileExistsError:
pass
ffmpeg_extract_subclip("video.mp4", start, end_seconds, targetname=f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip = VideoFileClip(f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip = clip.subclip(0, 60)
clip = clip.volumex(2)
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize = 50, color = 'white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
video = CompositeVideoClip([clip, txt_clip])
clip.write_videofile(f"result_{str(current_time)}/result_edit/cut_{str(cut_name_num)}.mp4")
except:
try:
os.makedirs(f"result_{str(current_time)}/result_edit")
except FileExistsError:
pass
ffmpeg_extract_subclip("video.mp4", start, video_duration, targetname=f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip_duration = duration_clip(f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip = VideoFileClip(f"result_{str(current_time)}/cut_{str(cut_name_num)}.mp4")
clip = clip.subclip(0, clip_duration)
clip = clip.volumex(2)
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize = 50, color = 'white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
video = CompositeVideoClip([clip, txt_clip])
clip.write_videofile(f"result_{str(current_time)}/result_edit/cut_{str(cut_name_num)}.mp4")
start += 60
cut_name_num += 1
end_seconds = start + 60
txt_part += 1
if __name__ == "__main__":
main()
使用进程,我只减少了 15-20 秒的时间,因为 ffmpeg
即使在单个进程中也几乎使用了全部 CPU 电源,而我的计算机没有电源 运行其他进程更快。
首先我减少了代码以使其更短。
try
和 except
中的代码具有相似的元素,因此我将它们移到 try/except
之外。
接下来我用了
if end > video_duration:
end = video_duration
而且我根本不需要 try/except
。
使用 os.makedirs(..., exist_ok=True)
我不需要 运行 它在 try/except
与此同时,我使用
将时间缩短了 20 秒 clip = VideoFileClip(filename).subclip(start, end)
而不是
temp_filename = f"{base_folder}/cut_{number}.mp4"
fmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
clip = VideoFileClip(temp_filename)
这样我就不会在磁盘上写入子剪辑,也不必再次从磁盘读取它。
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
import time
def main():
text = input("Enter Your text please: ") [::-1]
#text = 'Hello World'
base_folder = time.strftime("result_%Y_%m_%d_%H_%M_%S")
os.makedirs(f"{base_folder}/result_edit", exist_ok=True)
filename = "video.mp4"
#filename = "BigBuckBunny.mp4"
video_duration = VideoFileClip(filename).duration
number = 0 # instead of `cut_name_num` and `txt_part` because both had the same value
time_start = time.time()
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
clip_duration = end - start
print(f'[DEBUG] number: {number:2} | start: {start:6.2f} | end: {end:6.2f} | duration: {clip_duration:.2f}')
final_text = f"{number} {text}"
temp_filename = f"{base_folder}/cut_{number}.mp4"
final_filename = f"{base_folder}/result_edit/cut_{number}.mp4"
#ffmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
#clip = VideoFileClip(temp_filename)
clip = VideoFileClip(filename).subclip(start, end)
clip = clip.volumex(2)
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize=50, color='white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
video = CompositeVideoClip([clip, txt_clip])
video.write_videofile(final_filename)
# - after loop -
# because I use `number += 1` before loop so now `number` has number of subclips
print('number of subclips:', number)
time_end = time.time()
diff = time_end - time_start
print(f'time: {diff:.2f}s ({diff//60:02.0f}:{diff%60:02.2f})')
if __name__ == "__main__":
main()
接下来我将代码移动到带参数的函数中 my_process(filename, text, start, end, number, base_folder)
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
import time
def my_process(filename, text, start, end, number, base_folder):
clip_duration = end - start
print(f'[DEBUG] number: {number:2} | start: {start:6.2f} | end: {end:6.2f} | duration: {clip_duration:.2f}')
final_text = f"{number} {text}"
temp_filename = f"{base_folder}/cut_{number}.mp4"
final_filename = f"{base_folder}/result_edit/cut_{number}.mp4"
#print('[DEBUG] ffmpeg_extract_subclip')
#ffmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
#print('[DEBUG] VideoClip')
#clip = VideoFileClip(temp_filename)
clip = VideoFileClip(filename).subclip(start, end)
clip = clip.volumex(2)
#print('[DEBUG] TextClip')
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize=50, color='white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
#print('[DEBUG] CompositeVideoClip')
video = CompositeVideoClip([clip, txt_clip])
#print('[DEBUG] CompositeVideoClip write')
video.write_videofile(final_filename)
#print('[DEBUG] CompositeVideoClip end')
def main():
text = input("Enter Your text please: ") [::-1]
#text = 'Hello World'
base_folder = time.strftime("result_%Y_%m_%d_%H_%M_%S")
os.makedirs(f"{base_folder}/result_edit", exist_ok=True)
filename = "video.mp4"
#filename = "BigBuckBunny.mp4"
video_duration = VideoFileClip(filename).duration
number = 0 # instead of `cut_name_num` and `txt_part` because both had the same value
time_start = time.time()
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
my_process(filename, text, start, end, number, base_folder)
# - after loop -
# because I use `number += 1` before loop so now `number` has number of subclips
print('number of subclips:', number)
time_end = time.time()
diff = time_end - time_start
print(f'time: {diff:.2f}s ({diff//60:02.0f}:{diff%60:02.2f})')
if __name__ == "__main__":
main()
现在我可以 运行 使用标准模块 multiprocessing
在单独的进程中运行(或标准模块 threading, concurrent.futures or external modules Joblib, Ray,等等)。
它启动单进程
# it has to use named arguments`target=`, `args=`
p = multiprocessing.Process(target=my_process, args=(filename, text, start, end, number, base_folder))
p.start() # start it
但如果我在循环中使用它,那么我将同时启动许多进程。
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
import time
import multiprocessing
def my_process(filename, text, start, end, number, base_folder):
clip_duration = end - start
print(f'[DEBUG] number: {number:2} | start: {start:6.2f} | end: {end:6.2f} | duration: {clip_duration:.2f}')
final_text = f"{number} {text}"
temp_filename = f"{base_folder}/cut_{number}.mp4"
final_filename = f"{base_folder}/result_edit/cut_{number}.mp4"
#print('[DEBUG] ffmpeg_extract_subclip')
#ffmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
#print('[DEBUG] VideoClip')
#clip = VideoFileClip(temp_filename)
clip = VideoFileClip(filename).subclip(start, end)
clip = clip.volumex(2)
#print('[DEBUG] TextClip')
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize=50, color='white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
#print('[DEBUG] CompositeVideoClip')
video = CompositeVideoClip([clip, txt_clip])
#print('[DEBUG] CompositeVideoClip write')
video.write_videofile(final_filename)
#print('[DEBUG] CompositeVideoClip end')
def main():
text = input("Enter Your text please: ") [::-1]
#text = 'Hello World'
base_folder = time.strftime("result_%Y_%m_%d_%H_%M_%S")
os.makedirs(f"{base_folder}/result_edit", exist_ok=True)
filename = "video.mp4"
#filename = "BigBuckBunny.mp4"
video_duration = VideoFileClip(filename).duration
number = 0 # instead of `cut_name_num` and `txt_part` because both had the same value
time_start = time.time()
all_processes = []
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
print("add process:", number)
p = multiprocessing.Process(target=my_process, args=(filename, text, start, end, number, base_folder)) # it has to use `target=`, `args=`
p.start() # start it
all_processes.append(p) # keep it to use `join()`
# - after loop -
for p in all_processes:
p.join() # wait for the end of process
# because I use `number += 1` before loop so now `number` has number of subclips
print('number of subclips:', number)
time_end = time.time()
diff = time_end - time_start
print(f'time: {diff:.2f}s ({diff//60:02.0f}:{diff%60:02.2f})')
if __name__ == "__main__":
main()
11 个子剪辑的旧版本启动 11 个进程。使用 Pool(4)
您可以将所有进程放入池中,它会同时 运行 4 个进程。当一个进程完成任务时,它将使用新参数启动下一个进程。
这次我使用循环为所有进程创建带有参数的列表
args_for_all_processes = []
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
print("add process:", number)
args_for_all_processes.append( (filename, text, start, end, number, base_folder) )
我将此列表与 Pool
一起使用,它会完成剩下的工作。
# I have 4 CPU so I use Pool(4) - but without value it should automatically use `os.cpu_count()`
with multiprocessing.Pool(4) as pool:
results = pool.starmap(my_process, args_for_all_processes)
#print(results)
Pool
可能会以不同的顺序启动进程,但如果他们使用 return
发送一些结果,那么 Pool
将以正确的顺序给出结果。
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
from moviepy.editor import *
import time
import multiprocessing
def my_process(filename, text, start, end, number, base_folder):
clip_duration = end - start
print(f'[DEBUG] number: {number:2} | start: {start:6.2f} | end: {end:6.2f} | duration: {clip_duration:.2f}')
final_text = f"{number} {text}"
temp_filename = f"{base_folder}/cut_{number}.mp4"
final_filename = f"{base_folder}/result_edit/cut_{number}.mp4"
#print('[DEBUG] ffmpeg_extract_subclip')
#ffmpeg_extract_subclip(filename, start, end, targetname=temp_filename)
#print('[DEBUG] VideoClip')
#clip = VideoFileClip(temp_filename)
clip = VideoFileClip(filename).subclip(start, end)
clip = clip.volumex(2)
#print('[DEBUG] TextClip')
txt_clip = TextClip(final_text, font="font/VarelaRound-Regular.ttf", fontsize=50, color='white')
txt_clip = txt_clip.set_pos(("center","top")).set_duration(60)
#print('[DEBUG] CompositeVideoClip')
video = CompositeVideoClip([clip, txt_clip])
#print('[DEBUG] CompositeVideoClip write')
video.write_videofile(final_filename)
#print('[DEBUG] CompositeVideoClip end')
# return "OK" # you can use `return` to send result/information to main process.
def main():
text = input("Enter Your text please: ") [::-1]
#text = 'Hello World'
base_folder = time.strftime("result_%Y_%m_%d_%H_%M_%S")
os.makedirs(f"{base_folder}/result_edit", exist_ok=True)
filename = "video.mp4"
#filename = "BigBuckBunny.mp4"
video_duration = VideoFileClip(filename).duration
number = 0 # instead of `cut_name_num` and `txt_part` because both had the same value
time_start = time.time()
# first create list with arguments for all processes
args_for_all_processes = []
for start in range(0, int(video_duration), 60):
end = start + 60
if end > video_duration:
end = video_duration
number += 1
print("add process:", number)
args_for_all_processes.append( (filename, text, start, end, number, base_folder) )
# - after loop -
# next put all processes to pool
with multiprocessing.Pool(4) as pool: # I have 4 CPU so I use Pool(4) - but it should use `os.cpu_count()` in `Pool()
results = pool.starmap(my_process, args_for_all_processes)
#print(results)
# - after loop -
# because I use `number += 1` before loop so now `number` has number of subclips
print('number of subclips:', number)
time_end = time.time()
diff = time_end - time_start
print(f'time: {diff:.2f}s ({diff//60:02.0f}:{diff%60:02.2f})')
if __name__ == "__main__":
main()