Создаем графический интерфейс для редактирования видео с помощью Python и FFmpeg

В этой статье мы рассмотрим, как создать простой графический интерфейс (GUI) для редактирования видео с использованием Python и FFmpeg. Мы реализуем функционал для вырезания определенных фрагментов из видео и их объединения. Также рассмотрим, как автоматически подбирать размер окна интерфейса, чтобы все элементы были полностью видны.

Что такое FFmpeg?

FFmpeg — это мощный инструмент для обработки видео и аудио. С его помощью можно вырезать фрагменты видео, объединять их, изменять кодек и многое другое. В нашем примере мы будем использовать FFmpeg для вырезания и объединения видеофрагментов.

Что мы создадим?

Мы создадим приложение с графическим интерфейсом, которое позволит:

  1. Выбрать входное и выходное видео.
  2. Добавить временные интервалы (сегменты) для вырезания.
  3. Обработать видео, вырезав указанные фрагменты и объединив их.

Шаг 1: Установка необходимых инструментов

Перед началом работы убедитесь, что у вас установлены:

  • Python (рекомендуется версия 3.7 или выше).
  • Библиотека tkinter (входит в стандартную поставку Python).
  • FFmpeg (установите его через терминал или командную строку).

Установите FFmpeg, если он еще не установлен:

  • Windows: Скачайте и установите FFmpeg с официального сайта.
  • Linux: Используйте пакетный менеджер, например, sudo apt install ffmpeg.
  • macOS: Используйте Homebrew: brew install ffmpeg.

Шаг 2: Создание графического интерфейса

Мы будем использовать библиотеку tkinter для создания графического интерфейса. Вот основной код приложения:

import tkinter as tk
from tkinter import filedialog, messagebox
import subprocess

def cut_and_concat_video(input_video, output_video, segments):
    """
    Вырезает определенные фрагменты из видео и объединяет их.
    """
    try:
        temp_files = []
        for i, (start, end) in enumerate(segments):
            temp_file = f"temp_{i}.mp4"
            temp_files.append(temp_file)
            command = [
                "ffmpeg",
                "-i", input_video,
                "-ss", start,
                "-to", end,
                "-c", "copy",
                temp_file
            ]
            subprocess.run(command, check=True)

        with open("concat_list.txt", "w") as f:
            for temp_file in temp_files:
                f.write(f"file '{temp_file}'\n")

        concat_command = [
            "ffmpeg",
            "-f", "concat",
            "-safe", "0",
            "-i", "concat_list.txt",
            "-c", "copy",
            output_video
        ]
        subprocess.run(concat_command, check=True)

        for temp_file in temp_files:
            subprocess.run(["rm", temp_file], check=True)
        subprocess.run(["rm", "concat_list.txt"], check=True)

        messagebox.showinfo("Успех", "Видео успешно обработано!")
    except Exception as e:
        messagebox.showerror("Ошибка", f"Произошла ошибка: {e}")

def add_segment():
    """Добавляет новый сегмент в список."""
    start = start_entry.get()
    end = end_entry.get()
    if start and end:
        segments_listbox.insert(tk.END, f"{start} - {end}")
        start_entry.delete(0, tk.END)
        end_entry.delete(0, tk.END)
    else:
        messagebox.showwarning("Предупреждение", "Заполните оба поля (начало и конец).")

def process_video():
    """Обрабатывает видео на основе выбранных сегментов."""
    input_video = input_video_entry.get()
    output_video = output_video_entry.get()
    segments = []

    for item in segments_listbox.get(0, tk.END):
        start, end = item.split(" - ")
        segments.append((start, end))

    if not input_video or not output_video or not segments:
        messagebox.showwarning("Предупреждение", "Заполните все поля и добавьте сегменты.")
        return

    cut_and_concat_video(input_video, output_video, segments)

def select_input_video():
    """Выбирает входное видео."""
    file_path = filedialog.askopenfilename(filetypes=[])
    if file_path:
        input_video_entry.delete(0, tk.END)
        input_video_entry.insert(0, file_path)

def select_output_video():
    """Выбирает выходное видео."""
    file_path = filedialog.asksaveasfilename(defaultextension=".mp4", filetypes=[])
    if file_path:
        output_video_entry.delete(0, tk.END)
        output_video_entry.insert(0, file_path)

# Создаем графический интерфейс
root = tk.Tk()
root.title("Редактор видео с FFmpeg")

# Входное видео
input_frame = tk.Frame(root)
input_frame.pack(fill=tk.X, padx=10, pady=5)

tk.Label(input_frame, text="Входное видео:").pack(side=tk.LEFT)
input_video_entry = tk.Entry(input_frame, width=50)
input_video_entry.pack(side=tk.LEFT, padx=(10, 0))

select_input_button = tk.Button(input_frame, text="Выбрать", command=select_input_video)
select_input_button.pack(side=tk.LEFT, padx=(10, 0))

# Выходное видео
output_frame = tk.Frame(root)
output_frame.pack(fill=tk.X, padx=10, pady=5)

tk.Label(output_frame, text="Выходное видео:").pack(side=tk.LEFT)
output_video_entry = tk.Entry(output_frame, width=50)
output_video_entry.pack(side=tk.LEFT, padx=(10, 0))

select_output_button = tk.Button(output_frame, text="Выбрать", command=select_output_video)
select_output_button.pack(side=tk.LEFT, padx=(10, 0))

# Добавление сегментов
segments_frame = tk.Frame(root)
segments_frame.pack(fill=tk.X, padx=10, pady=5)

tk.Label(segments_frame, text="Сегменты:").pack(side=tk.LEFT)
start_entry = tk.Entry(segments_frame, width=10)
start_entry.pack(side=tk.LEFT, padx=(10, 0))
tk.Label(segments_frame, text="до").pack(side=tk.LEFT, padx=(10, 0))
end_entry = tk.Entry(segments_frame, width=10)
end_entry.pack(side=tk.LEFT, padx=(10, 0))

add_segment_button = tk.Button(segments_frame, text="Добавить", command=add_segment)
add_segment_button.pack(side=tk.LEFT, padx=(10, 0))

# Список сегментов
segments_listbox = tk.Listbox(root, width=60, height=10)
segments_listbox.pack(padx=10, pady=10)

# Кнопка обработки
process_button = tk.Button(root, text="Обработать видео", command=process_video)
process_button.pack(pady=10)

# Автоматически подбираем размер окна
root.update_idletasks()
root.geometry(f"{root.winfo_width()}x{root.winfo_height()}")

# Запуск приложения
root.mainloop()

Шаг 3: Как работает приложение

  1. Выбор видео:
    • Нажмите кнопку “Выбрать” рядом с полем “Входное видео”, чтобы выбрать файл для обработки.
    • Нажмите кнопку “Выбрать” рядом с полем “Выходное видео”, чтобы указать, куда сохранить результат.
  2. Добавление сегментов:
    • Введите время начала и конца фрагмента в формате “чч:мм:сс”.
    • Нажмите кнопку “Добавить”, чтобы добавить сегмент в список.
  3. Обработка видео:
    • После добавления всех сегментов нажмите кнопку “Обработать видео”.
    • Программа вырежет указанные фрагменты и объединит их в одно видео.

Автоматический подбор размера окна

Чтобы окно интерфейса автоматически подстраивалось под содержимое, мы используем следующие строки кода:

root.update_idletasks()
root.geometry(f"{root.winfo_width()}x{root.winfo_height()}")

Этот код обновляет размеры окна перед его отображением, чтобы все элементы интерфейса были полностью видны.