初投稿です.よろしくお願いします.
*この記事の続きはこちら
概要
やりたいこと
- pythonからffmpegを使って動画を処理したい.
- GUI化したい.
GUIの内容
- ボタンを押すと処理が開始する.
- 処理中はtkinterのプログレスバー(不確定モード)のウインドウがポップアップされる.
- 処理が完了するとプログレスバーのウインドウが自動的に閉じる.
コード
NGな例その1
import os, subprocess
import tkinter as tk
from tkinter import ttk, messagebox
command = "ffmpeg hogehoge" # ffmpegの処理コマンド
def start():
progress = tk.Toplevel()
bar = ttk.Progressbar(progress,mode='indeterminate')
bar.pack()
bar.start()
subprocess.run(command, shell=True)
progress.destroy()
root = tk.Tk()
button = tk.Button(root, text = "start", command = start)
button.pack()
root.mainloop()
ffmpegの処理は始まるが,プログレスバーは表示されない.rootウインドウも応答なしになる.
NGな例その2
-
subprocess.run
を非同期処理が可能なsubprocess.Popen
にするとどうなる?
→ffmpegの処理開始と同時にprogress.destroy()
が実行されるので,プログレスバーは表示されない.そこで,同期待ちが必要.
OKな例
import os, subprocess
import tkinter as tk
from tkinter import ttk
import threading
command = "ffmpeg hogehoge" # ffmpegの処理コマンド
def start():
progress = tk.Toplevel()
bar = ttk.Progressbar(progress,mode='indeterminate')
bar.pack()
bar.start()
def process():
p = subprocess.Popen(command, shell=True)
try:
outs, errs = p.communicate()
except subprocess.TimeoutExpired:
pass
else:
p.terminate()
progress.destroy()
th1 = threading.Thread(target=process)
th1.start()
root = tk.Tk()
button = tk.Button(root, text = "start", command = start)
button.pack()
root.mainloop()
ポイント
-
subprocess.run
ではなくsubprocess.Popen
を使う. -
threading
で別スレッドでffmpegを実行する. -
outs, errs = p.communicate()
でffmpegの処理待ちを行う.
発展
- 標準出力をプログレスバーウインドウにリアルタイム表示する(参考:stackoverflow - FFMPEG and Pythons subprocess).
- 処理終了後にポップアップウインドウを表示する.
import os, subprocess
import tkinter as tk
from tkinter import ttk, messagebox
import threading
command = "ffmpeg hogehoge" # ffmpegの処理コマンド
def start():
progress = tk.Toplevel()
progress.geometry("600x75")
progress.title("processing...")
info_text = tk.StringVar()
info = tk.Label(progress, textvariable = info_text)
info.pack(side = tk.TOP, anchor = tk.W)
bar = ttk.Progressbar(progress,mode='indeterminate')
bar.pack(side = tk.TOP, fill = tk.X)
bar.start()
def process():
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,shell=True,universal_newlines=True)
for line in p.stdout:
info_text.set(line)
try:
outs, errs = p.communicate()
except subprocess.TimeoutExpired:
pass
else:
p.terminate()
progress.destroy()
warnwindow = messagebox.showwarning("Done", "Animation saved!")
th1 = threading.Thread(target=process)
th1.start()
root = tk.Tk()
button = tk.Button(root, text = "start", command = start)
button.pack()
root.mainloop()
今後
- キャンセルボタンがあるとよい.
- 確定モードのプログレスバーと標準出力の進捗を同期させたい.
最後までお読みいただきありがとうございました.