diff options
-rw-r--r-- | preview.py | 89 | ||||
-rw-r--r-- | vidslice.py | 19 |
2 files changed, 101 insertions, 7 deletions
diff --git a/preview.py b/preview.py new file mode 100644 index 0000000..f22c6ba --- /dev/null +++ b/preview.py @@ -0,0 +1,89 @@ +import subprocess +import tempfile +import threading +from tkinter import * +from tkinter import ttk + +from options import FFmpegOptions + + +class PreviewPanel(ttk.LabelFrame): + def __init__(self, *args, get_ffmpeg_args=lambda: FFmpegOptions([], []), get_frame_count=lambda: 0, **kw): + super(PreviewPanel, self).__init__(*args, text='Preview', **kw) + self.input_path = None + self.get_ffmpeg_args = get_ffmpeg_args + self.get_frame_count = get_frame_count + + def button(text, command, column): + ttk.Button(self, text=text, command=command).grid(column=column, row=0, sticky=(N, W, S, E)) + self.columnconfigure(column, weight=1) + + button("Preview Start", self.preview_start, 0) + button("Preview Middle", self.preview_middle, 1) + button("Preview End", self.preview_end, 2) + + self.image = None + self.image_label = ttk.Label(self, anchor='center') + self.image_label.grid(column=0, row=1, columnspan=3, sticky=(N, W, S, E)) + self.rowconfigure(1, weight=1) + + self.enable(False) + + def preview_at(self, offset): + offset = int(offset) + self.enable(False) + real_args = self.get_ffmpeg_args() + input_args = real_args.input + width = self.image_label.winfo_width() + height = self.image_label.winfo_height() + real_args.vf += [ + rf'select=eq(n\,{offset})', + f'scale=w={width}:h={height}:force_original_aspect_ratio=decrease' + ] + real_args.output += ['-frames:v', '1'] + output_args = real_args.output_with_vf() + + def run(): + _, output_path = tempfile.mkstemp(suffix='.png') + args = ['ffmpeg', '-hide_banner', '-v', 'warning', '-y'] + input_args + \ + ['-i', self.input_path] + output_args + [output_path] + print(args) + # noinspection PyArgumentList + proc = subprocess.Popen(args, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, text=True, creationflags=subprocess.CREATE_NO_WINDOW) + while proc.poll() is None: + out_data = proc.stdout.readline() + if out_data != '': + print(out_data, end='') + self.enable(True) + self.image = PhotoImage(file=output_path) + self.image_label['image'] = self.image + + threading.Thread(target=run).start() + + def preview_start(self, *args): + self.preview_at(0) + + def preview_middle(self, *args): + self.preview_at(self.get_frame_count() / 2) + + def preview_end(self, *args): + self.preview_at(self.get_frame_count() - 1) + + def enable(self, enabled): + state = 'disabled' + if enabled: + state = '!' + state + self.state([state]) + for child in self.winfo_children(): + try: + child.state([state]) + except AttributeError: + pass + + def set_input_path(self, path, data): + self.enable(data is not None) + if data is None: + self.input_path = None + else: + self.input_path = path diff --git a/vidslice.py b/vidslice.py index 632e426..eca036c 100644 --- a/vidslice.py +++ b/vidslice.py @@ -7,6 +7,7 @@ from tkinter import ttk from options import OptionsPanel from output import OutputPanel +from preview import PreviewPanel from sources import SourcesPanel, update_ytdl VERSION = "1.6" @@ -45,20 +46,24 @@ class VidsliceFrame: root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) - # set up sources panel self.sources_panel = SourcesPanel(mainframe) - self.sources_panel.grid(column=0, row=0, columnspan=2, sticky=(W, E), padx=5, pady=5) + self.sources_panel.grid(column=0, row=0, columnspan=2, sticky=(W, E, N, S), padx=5, pady=5) - # set up options panel self.options_panel = OptionsPanel(mainframe) - self.options_panel.grid(column=0, row=1, sticky=(W, E, N), padx=5, pady=5) - mainframe.rowconfigure(1, weight=1) + self.options_panel.grid(column=0, row=1, columnspan=2, sticky=(W, N, S), padx=5, pady=5) self.sources_panel.on_update(self.options_panel.update_info) - # set up output panel + self.preview_panel = PreviewPanel(mainframe, get_ffmpeg_args=self.options_panel.ffmpeg_opts, + get_frame_count=self.options_panel.frame_count) + self.preview_panel.grid(column=0, row=2, sticky=(W, E, N, S), padx=5, pady=5) + mainframe.rowconfigure(2, weight=1) + mainframe.columnconfigure(0, weight=2) + self.sources_panel.on_update( + lambda data: self.preview_panel.set_input_path(self.sources_panel.get_file(), data)) + self.output_panel = OutputPanel(mainframe, get_ffmpeg_args=self.options_panel.ffmpeg_opts, get_frame_count=self.options_panel.frame_count) - self.output_panel.grid(column=1, row=1, sticky=(W, E, N, S), padx=5, pady=5) + self.output_panel.grid(column=1, row=2, sticky=(W, E, N, S), padx=5, pady=5) mainframe.columnconfigure(1, weight=1) self.sources_panel.on_update(lambda data: self.output_panel.set_input_path(self.sources_panel.get_file(), data)) |