Создание видео‑плеера на Python с Tkinter, VLC и datetime

Что делает этот проект
Этот проект показывает, как собрать базовый видео‑плеер, который:
- открывает локальные видеофайлы (.mp4/.avi);
- воспроизводит, ставит на паузу, останавливает, перематывает и ускоряет воспроизведение;
- отображает прогресс и время в формате HH:MM:SS;
- использует Tkinter для интерфейса и python-vlc для воспроизведения.
Зачем это полезно: вы получаете практику в создании настольных приложений, обработке мультимедиа и управлении событиями в GUI.
Коротко о компонентах (одной строкой)
- Tkinter — стандартная библиотека для создания GUI в Python.
- python-vlc — обёртка вокруг библиотеки VLC (VideoLAN) для управления воспроизведением.
- datetime (timedelta) — для форматирования времени в HH:MM:SS.
Важно: tkinter часто уже установлен с дистрибутивом Python, но на некоторых системах его нужно установить отдельно (см. раздел Установка).
Установка и системные требования
Рекомендуемая среда: Python 3.7+.
Установка зависимостей:
- python-vlc: pip install python-vlc
Tkinter:
- Windows / macOS: обычно входит в комплект Python.
- Linux (Debian/Ubuntu): sudo apt install python3-tk
Дополнительно: VLC (сам плеер/библиотеки) должен присутствовать в системе. На Linux это чаще всего пакет libvlc; на Windows установщик VLC добавит нужные библиотеки.
Советы по установке:
- Если python-vlc не находит libvlc, убедитесь, что версия VLC (32/64 бита) совпадает с вашей версией Python.
- На macOS иногда требуется установить VLC через Homebrew или официальный инсталлятор.
Архитектура приложения — кратко
Приложение организовано вокруг класса MediaPlayerApp (наследник tk.Tk). Логика разбита на методы:
- initialize_player — создаёт экземпляр vlc.Instance и media_player;
- create_widgets — создаёт холст для видео, кнопки управления, метку времени и полосу прогресса;
- select_file — диалог выбора файла и запуск воспроизведения;
- play_video / pause_video / stop / fast_forward / rewind — управляющие действия;
- get_duration_str / update_video_progress — получение и обновление времени;
- VideoProgressBar — пользовательский виджет полосы прогресса на основе tk.Scale.
Ниже — основной пример кода, адаптированный для удобного чтения и с типичным кроссплатформенным установлентием окна вывода видео.
import sys
import tkinter as tk
import vlc
from tkinter import filedialog
from datetime import timedelta
class MediaPlayerApp(tk.Tk):
def __init__(self):
super().__init__()
self.title("Media Player")
self.geometry("800x600")
self.configure(bg="#f0f0f0")
self.initialize_player()
def initialize_player(self):
self.instance = vlc.Instance()
self.media_player = self.instance.media_player_new()
self.current_file = None
self.playing_video = False
self.video_paused = False
self.create_widgets()
def create_widgets(self):
self.media_canvas = tk.Canvas(self, bg="black", width=800, height=400)
self.media_canvas.pack(pady=10, fill=tk.BOTH, expand=True)
self.select_file_button = tk.Button(
self,
text="Select File",
font=("Arial", 12, "bold"),
command=self.select_file,
)
self.select_file_button.pack(pady=5)
self.time_label = tk.Label(
self,
text="00:00:00 / 00:00:00",
font=("Arial", 12, "bold"),
fg="#555555",
bg="#f0f0f0",
)
self.time_label.pack(pady=5)
self.control_buttons_frame = tk.Frame(self, bg="#f0f0f0")
self.control_buttons_frame.pack(pady=5)
self.play_button = tk.Button(
self.control_buttons_frame,
text="Play",
font=("Arial", 12, "bold"),
bg="#4CAF50",
fg="white",
command=self.play_video,
)
self.play_button.pack(side=tk.LEFT, padx=5, pady=5)
self.pause_button = tk.Button(
self.control_buttons_frame,
text="Pause",
font=("Arial", 12, "bold"),
bg="#FF9800",
fg="white",
command=self.pause_video,
)
self.pause_button.pack(side=tk.LEFT, padx=10, pady=5)
self.stop_button = tk.Button(
self.control_buttons_frame,
text="Stop",
font=("Arial", 12, "bold"),
bg="#F44336",
fg="white",
command=self.stop,
)
self.stop_button.pack(side=tk.LEFT, pady=5)
self.fast_forward_button = tk.Button(
self.control_buttons_frame,
text="Fast Forward",
font=("Arial", 12, "bold"),
bg="#2196F3",
fg="white",
command=self.fast_forward,
)
self.fast_forward_button.pack(side=tk.LEFT, padx=10, pady=5)
self.rewind_button = tk.Button(
self.control_buttons_frame,
text="Rewind",
font=("Arial", 12, "bold"),
bg="#2196F3",
fg="white",
command=self.rewind,
)
self.rewind_button.pack(side=tk.LEFT, pady=5)
self.progress_bar = VideoProgressBar(
self, self.set_video_position, bg="#e0e0e0", highlightthickness=0
)
self.progress_bar.pack(fill=tk.X, padx=10, pady=5)
def select_file(self):
file_path = filedialog.askopenfilename(
filetypes=[("Media Files", "*.mp4 *.avi")]
)
if file_path:
self.current_file = file_path
# Время будет вычислено после старта плеера
self.time_label.config(text="00:00:00 / " + self.get_duration_str())
self.play_video()
def get_duration_str(self):
if self.playing_video:
total_duration = self.media_player.get_length()
total_duration_str = str(timedelta(milliseconds=total_duration))[:-3]
return total_duration_str
return "00:00:00"
def play_video(self):
if not self.playing_video and self.current_file:
media = self.instance.media_new(self.current_file)
self.media_player.set_media(media)
# Кроссплатформенное привязание окна вывода
if sys.platform.startswith('win'):
self.media_player.set_hwnd(self.media_canvas.winfo_id())
elif sys.platform.startswith('linux'):
self.media_player.set_xwindow(self.media_canvas.winfo_id())
elif sys.platform == 'darwin':
self.media_player.set_nsobject(self.media_canvas.winfo_id())
self.media_player.play()
self.playing_video = True
def fast_forward(self):
if self.playing_video:
current_time = self.media_player.get_time() + 10000
self.media_player.set_time(current_time)
def rewind(self):
if self.playing_video:
current_time = self.media_player.get_time() - 10000
self.media_player.set_time(max(0, current_time))
def pause_video(self):
if self.playing_video:
if self.video_paused:
self.media_player.play()
self.video_paused = False
self.pause_button.config(text="Pause")
else:
self.media_player.pause()
self.video_paused = True
self.pause_button.config(text="Resume")
def stop(self):
if self.playing_video:
self.media_player.stop()
self.playing_video = False
self.time_label.config(text="00:00:00 / " + self.get_duration_str())
def set_video_position(self, value):
if self.playing_video:
total_duration = self.media_player.get_length()
position = int((float(value) / 100) * total_duration)
self.media_player.set_time(position)
def update_video_progress(self):
if self.playing_video:
total_duration = self.media_player.get_length()
current_time = self.media_player.get_time()
if total_duration > 0:
progress_percentage = (current_time / total_duration) * 100
self.progress_bar.set(progress_percentage)
current_time_str = str(timedelta(milliseconds=current_time))[:-3]
total_duration_str = str(timedelta(milliseconds=total_duration))[:-3]
self.time_label.config(text=f"{current_time_str} / {total_duration_str}")
self.after(1000, self.update_video_progress)
class VideoProgressBar(tk.Scale):
def __init__(self, master, command, kwargs):
kwargs["showvalue"] = False
super().__init__(
master,
from_=0,
to=100,
orient=tk.HORIZONTAL,
length=800,
command=command,
kwargs,
)
self.bind("", self.on_click)
def on_click(self, event):
if self.cget("state") == tk.NORMAL:
value = (event.x / self.winfo_width()) * 100
self.set(value)
if __name__ == "__main__":
app = MediaPlayerApp()
app.update_video_progress()
app.mainloop() Примечания по коду и подробности реализации
- Привязка окна вывода VLC зависит от платформы: set_hwnd (Windows), set_xwindow (Linux), set_nsobject (macOS). Неправильный метод приводит к отсутствию видео в холсте, хотя звук может идти.
- media_player.get_length() и get_time() возвращают значения в миллисекундах. Перед форматированием следует проверять, что get_length() > 0, иначе деление даст ошибку.
- Некоторые кодеки/контейнеры могут не предоставлять длину сразу после play(); в таких случаях можно повторно запрашивать длину через небольшую задержку.
Important: если плеер не запускается, проверьте, доступна ли библиотека libvlc, и совпадает ли архитектура (32/64 бит) с Python.
Отладка и распространённые проблемы
- «Видео не отображается, только звук»: скорее всего, неверный method привязки окна. Проверьте platform и используйте соответствующий метод.
- «media_player.get_length() возвращает -1»: это значит, что длительность ещё не определена. Подождите несколько сотен миллисекунд после play() и попробуйте снова.
- «Ошибка при импорте tkinter»: установите пакет python3-tk (Linux) или убедитесь, что используете стандартный Python с включённым Tk.
- Проблемы с путями к файлам с кириллицей: убедитесь, что кодировка файловой системы поддерживается, и используйте пути в формате Unicode (строки Python 3 уже поддерживают это).
Тестирование и критерии приёмки
Критерии приёмки:
- При выборе файла воспроизведение начинается автоматически.
- Кнопки Play/Pause/Stop/Fast Forward/Rewind работают корректно.
- Полоса прогресса отражает текущее положение и позволяет переходить по клику/перетаскиванию.
- Время отображается в формате HH:MM:SS и корректно обновляется.
Минимальные тесты (Test cases):
- Открыть .mp4, проверить, что видео и звук воспроизводятся.
- Нажать Pause — воспроизведение приостанавливается; кнопка меняет текст на Resume.
- Нажать Fast Forward — позиция увеличилась примерно на 10 секунд.
- Перемещение по прогресс‑бару — видео переходит к соответствующему моменту.
- Выбрать файл с кириллическим именем — открывается и воспроизводится.
Роль‑ориентированные чеклисты
Разработчик:
- Проверить корректность привязки окна для каждой ОС.
- Обработать ошибки get_length() == -1.
- Добавить логи для ошибок libvlc.
Тестировщик:
- Прогнать тесты из раздела выше на Windows/macOS/Linux.
- Проверить работу с разными кодеками и контейнерами.
Конечный пользователь (README):
- Установить VLC и python-vlc.
- Запустить скрипт и выбрать файл через кнопку Select File.
Варианты расширения (идеи)
- Поддержка субтитров (загрузка .srt через vlc.Media.add_slave или использование функционала VLC).
- Регулировка громкости и mute.
- Изменение соотношения сторон и масштабирования видео.
- Плейлист и очередь воспроизведения.
- Горячие клавиши для основных действий.
Альтернативные подходы:
- Pygame / SDL — можно использовать для рендеринга и управления мультимедиа в более игровом контексте.
- PyQt / PySide — для более современного интерфейса и расширенной виджетной базы.
Кого выбрать: если нужна простота и отсутствие внешних зависимостей от GUI‑фреймворка — Tkinter + python-vlc подходит. Для более «desktop»-ориентированного интерфейса — PyQt/PySide рекомендуется.
Мозговые модели и рекомендации по реализации (heuristics)
- Разделяйте GUI и логику управления плеером: медиа‑операции — в отдельном слое, GUI только отправляет команды и отображает состояние.
- Всегда проверяйте возвращаемые значения vlc (длительность, текущее время) и защищайте от деления на ноль.
- Делегируйте обновление UI в основной поток Tkinter через after(), чтобы не блокировать окно.
Совместимость и локальные нюансы
- Windows: используйте set_hwnd. Убедитесь, что VLC установлен и видим в PATH при использовании python-vlc.
- Linux: возможно, потребуется установить пакеты libvlc-dev и сборки для поддержки конкретных кодеков.
- macOS: для set_nsobject иногда нужно дополнительно разбирать типы объектов Cocoa; проверяйте документацию python-vlc.
Локальные рекомендации для русскоязычных пользователей:
- Диалог открытия файла корректно работает с кириллицей в имени. Если возникают проблемы, тестируйте в окружении с UTF‑8 по умолчанию.
Безопасность и приватность
- Программа работает локально и не отправляет данные по сети по умолчанию.
- Если добавляете функциональность сетевой загрузки, учтите обработку опасных форматов и проверку целостности.
Небольшой плейбук для добавления новой функциональности (mini‑methodology)
- Запланировать требование и критерии приёмки.
- Добавить интерфейс (кнопка/меню) и заглушку‑обработчик.
- Реализовать логику в отдельном методе MediaPlayerApp.
- Написать тесты и прогнать их на всех целевых ОС.
- Провести ручное тестирование с разнообразными файлами.
Примеры улучшений: короткие сниппеты
- Установка громкости:
# volume: 0..100
self.media_player.audio_set_volume(80)- Проверка готовности длительности с таймаутом:
def wait_for_length(player, timeout_ms=2000):
import time
waited = 0
while player.get_length() <= 0 and waited < timeout_ms:
time.sleep(0.1)
waited += 100Скриншоты интерфейса (оригинальные файлы)
Когда вы выбираете видео, оно автоматически стартует, а метки времени обновляются.
При нажатии Pause кнопка меняет текст на Resume; Fast Forward пропускает ~10 секунд.
Когда этот подход может не подойти (counterexamples)
- Требуется аппаратное ускорение специфичного видеодекодирования: VLC его поддерживает, но могут потребоваться дополнительные настройки или другие библиотеки.
- Нужен очень «тяжёлый» UI с большим количеством кастомизации — лучше использовать Qt.
Итоговое резюме
Создание базового видео‑плеера на Python с Tkinter и python-vlc — хороший учебный проект, который даёт практику в GUI, обработке мультимедиа и управлении состоянием. Начните с минимального примера, проверьте кроссплатформенную привязку окна вывода и затем добавляйте функции: субтитры, регуляторы громкости, плейлисты.
Важно: тестируйте на целевых системах и учитывайте различия в поведении библиотеки VLC на разных платформах.
Похожие материалы
Как найти и выбрать зарядные станции для электромобиля
Трекер чтения и виртуальная полка в Notion
Сберегательный счёт Apple для держателей Apple Card
Карточки в Google Таблицах: Flippity шаг за шагом