Python 使用moviepy进行多处理
最近,我制作了一个脚本,用5分钟的视频剪辑和5个视频的剪辑,每个视频1分钟,效果很好,但对于像我这样的pc来说,时间太长,而且我的pc的部件性能非常好: 英特尔(R)核心(TM)i7-10700 CPU@2.90GHz,2904 Mhz,8核,16 逻辑处理器 已安装的物理内存(RAM)16.0 GB 所以我在moviepy的文档“线程”中搜索,我在“write_videofile”函数中找到了一些东西,我可以设置我的线程以加快速度,我尝试了它,但它不起作用,我的意思是它起作用了,但只是它可能变为2或3 it/s以上 我还发现了带有多线程的示例代码,但似乎代码不起作用,因为moviepy库中不存在moviepy.multi-threading,请帮助我加快渲染速度, 多谢各位 以下是我找到的代码:Python 使用moviepy进行多处理,python,moviepy,Python,Moviepy,最近,我制作了一个脚本,用5分钟的视频剪辑和5个视频的剪辑,每个视频1分钟,效果很好,但对于像我这样的pc来说,时间太长,而且我的pc的部件性能非常好: 英特尔(R)核心(TM)i7-10700 CPU@2.90GHz,2904 Mhz,8核,16 逻辑处理器 已安装的物理内存(RAM)16.0 GB 所以我在moviepy的文档“线程”中搜索,我在“write_videofile”函数中找到了一些东西,我可以设置我的线程以加快速度,我尝试了它,但它不起作用,我的意思是它起作用了,但只是它可能变
从moviepy.multi-threading导入multi-thread\u write\u视频文件
def concat_clips():
文件=[
“myclip1.mp4”,
“myclip2.mp4”,
“myclip3.mp4”,
“myclip4.mp4”,
]
多线程写入视频文件(“output.mp4”,获取最终剪辑,{“files”:files})
def get_最终_剪辑(文件):
clips=[视频文件剪辑(文件)用于文件中的文件]
最终=连接视频剪辑(剪辑,方法=“合成”)
返回决赛
这是我的代码:
从moviepy.video.io.ffmpeg\u工具导入ffmpeg\u提取\u子剪辑
从moviepy.editor导入*
从numpy导入数组中,选择true_divide
进口cv2
导入时间
#ffmpeg_extract_subclip(“full.mp4”、开始秒、结束秒、targetname=“cut.mp4”)
def duration_剪辑(文件名):
clip=VideoFileClip(文件名)
持续时间=clip.duration
返回持续时间
当前\u时间=时间.strftime(“%Y\u%m\u%d\u%H\u%m\u%S”)
def main():
全局持续时间
开始=0
切割\u名称\u数量=1
结束时间=开始时间+60秒
视频持续时间=持续时间剪辑(“video.mp4”)
txt=输入(“请输入您的文本:”)[:-1]
txt_部分=1
当开始
使用进程我只减少了15-20秒的时间,因为即使是在单个进程中,我的计算机也几乎耗尽了CPU的全部能力,无法更快地运行其他进程
首先,我减少了代码,使其更短
try
和except
中的代码具有相似的元素,因此我将它们移到了try/except
之外
接下来我用
if end > video_duration:
end = video_duration
我根本不需要尝试/除了
使用os.makedirs(…,exist\u ok=True)
我不需要在try/except中运行它
同时,我使用
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)
这样,我就不需要在磁盘上写subclip,也不需要从磁盘上再次读取它
接下来,我将代码移动到带有参数的函数myu进程(文件名、文本、开始、结束、编号、基本文件夹)
现在我可以使用标准模块在单独的进程中运行函数
(或标准模块或外部模块等)
它只启动一个进程
# 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
但如果我在循环中使用它,那么我将同时启动许多进程
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) )
我将这个列表与池一起使用,它将完成其余的工作
# 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()
我想知道如何能够在线程中连接文件。至于我,你们不能在你们写完第一个文件之前开始写第二个文件,所以第二个文件依赖于第一个文件,并没有地方把它分成两个线程。若因为创建了fi而必须剪切文件,则可以拆分该问题
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) )
# 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)
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()