如何为ffmpeg-python进程实现多线程并支持中途终止?
解决Tkinter中终止FFmpeg音视频合并进程的问题
问题根源
你的代码存在两个核心问题:
ffmpeg.output().run()是阻塞调用,会占用线程直到FFmpeg执行完毕,导致start_ffmpeg里的while循环无法实时检查is_cancelled状态start_ffmpeg中的while循环会在每次迭代启动新的FFmpeg线程,这会重复执行合并任务,完全不符合预期
修正方案
我们需要获取FFmpeg的进程实例,这样就能在点击取消按钮时主动终止它,同时修正线程逻辑避免重复启动任务:
from tkinter import * import ffmpeg import threading # 全局变量保存FFmpeg进程实例和取消状态 ffmpeg_process = None is_cancelled = False def start_ffmpeg_thread(audio_part, video_part, path): # 避免重复启动任务 global is_cancelled, ffmpeg_process if ffmpeg_process is not None: return is_cancelled = False threading.Thread(target=start_ffmpeg, args=(audio_part, video_part, path), daemon=True).start() def start_ffmpeg(audio_part, video_part, path): global ffmpeg_process try: # 使用run_async=True获取FFmpeg的Popen进程对象,非阻塞执行 ffmpeg_process = ffmpeg.output(audio_part, video_part, path).run(overwrite_output=True, run_async=True) # 循环检查取消状态,同时等待FFmpeg进程结束 while ffmpeg_process.poll() is None: if is_cancelled: # 终止FFmpeg进程 ffmpeg_process.terminate() # 等待进程退出 ffmpeg_process.wait() break finally: # 重置进程状态 ffmpeg_process = None def cancel_ffmpeg(): global is_cancelled is_cancelled = True root = Tk() video_part = ffmpeg.input("<path_video_part>") audio_part = ffmpeg.input("<path_audio_part>") path = "<path>" button_1 = Button(root, text="Start", command=lambda: start_ffmpeg_thread(audio_part, video_part, path)) button_1.pack(pady=30, padx=30) button_2 = Button(root, text="Stop", command=cancel_ffmpeg) button_2.pack(pady=30, padx=30) root.mainloop()
关键修改点
- 使用
run_async=True调用FFmpeg,返回subprocess.Popen对象,让FFmpeg在后台执行,不阻塞线程 - 在循环中通过
ffmpeg_process.poll()检查FFmpeg是否运行,同时实时检测is_cancelled状态 - 取消时调用
ffmpeg_process.terminate()终止进程,确保任务中途停止 - 添加重复启动检查,避免多次点击Start按钮启动多个合并任务
- 使用
daemon=True标记线程,确保关闭Tkinter窗口时线程能自动退出
内容的提问来源于stack exchange,提问作者duruburak
相关产品推荐
相关产品推荐

