Рубрики
Без рубрики

Как построить медиаплеер Python с помощью LibVLC и GTK+

В этом уроке мы узнаем, как создать мультимедийное приложение на Python с помощью LibVLC и GTK+, которое воспроизводит мультимедиа при его запуске. Пользователи приложения также смогут управлять основными параметрами воспроизведения.

Автор оригинала: Prince.

В этом уроке мы узнаем, как создать мультимедийное приложение на Python с помощью LibVLC и GTK+ , которое воспроизводит мультимедиа при его запуске. Пользователи приложения также смогут управлять основными параметрами воспроизведения.

Этот учебник предполагает, что читатели знают, как создавать и запускать файлы Python; понимают основные ошибки интерпретатора; работают со строками, поплавками и булевыми значениями; ориентируются на объект; и представление о потоках в Python. Есть и другие аккуратные советы по питону, о которых стоит знать.

Учебник подходит для начинающих и средних программистов. Этот учебник охватывает GTK+ версии 3 и LibVLC media framework; он был создан и протестирован на Linux.

LibVLC

Это внешний программный интерфейс VLC media player. LibVLC (VLC SDK) – это основной движок и интерфейс мультимедийной платформы, на которой основан VLC media player. Он может быть встроен в приложения для получения мультимедийных возможностей. Поэтому приложение должно иметь те же функции, что и VLC media player.

Зависимости

VLC разработан на языке C, поэтому установите его перед использованием через Python.Привязки Python имеют полный охват API LibVLC, а сгенерированный модуль находится в чистом Python. Это зависит только от типов .

Скачать vlc.py модуль из репозитория Git и поместите модуль в место, доступное Python.

GTK+

Инструментарий для создания графических пользовательских интерфейсов, написанных на языке программирования Си.

Вы также должны знать об этих вещах:

  • GDK : набор GIMP Drawing Kit находится между библиотекой xlib и библиотекой GTK+, обрабатывая базовые рендеринги, такие как примитивы рисования, растровая графика (растровые изображения), курсоры, шрифты, а также оконные события и функции перетаскивания. Он содержит бэк-энды к нескольким оконным системам, таким как X11.

  • GdkX11 : Также является частью пакета GObject для взаимодействия с X Window System и специфичных для X backend функций.

  • PyGObject : Модуль Python ,который позволяет разработчикам получать доступ к библиотекам на основе GObject, таким как GTK+, Gdk, Gdk X11 и т. Д.

Установка

PyGObject и его зависимости упаковываются всеми основными дистрибутивами Linux. Итак, установите пакет из официального репозитория дистрибутива.

В приведенном ниже блоке кода показано, как импортировать библиотеку Gtk+ из пакета GI (gobject-introspection). Поскольку пользователи могут иметь несколько версий GTK+ в своих системах, импортируйте GTK, который относится к GTK+ 3, а не к какой-либо другой версии библиотеки, что является целью оператора gi.require_version('Gtk', '3.0') .

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

Компоненты приложения

I. Окно приложения

Это подкласс Gtk.Window чтобы определить свой собственный Application Window класс для создания окна верхнего уровня, содержащего другие виджеты.

В конструкторе класса вызовите конструктор суперкласса и задайте значение заголовка свойства Python-Vlc Media Player .

class ApplicationWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="Python-Vlc Media Player")

Кнопки управления мультимедиа

        self.playback_button = Gtk.Button()
        self.stop_button = Gtk.Button()

Изображения, отображаемые на кнопках

Мы используем встроенные изображения, предоставляемые библиотекой GTK+.

        self.play_image = Gtk.Image.new_from_icon_name(
                "gtk-media-play",
                Gtk.IconSize.MENU
            )
        self.pause_image = Gtk.Image.new_from_icon_name(
                "gtk-media-pause",
                Gtk.IconSize.MENU
            )
        self.stop_image = Gtk.Image.new_from_icon_name(
                "gtk-media-stop",
                Gtk.IconSize.MENU
            )

Установите изображения на кнопках.

        self.playback_button.set_image(self.play_image)
        self.stop_button.set_image(self.stop_image)
Медиаплеер Python

события и сигналы в GTK+

  • GTK+-это система, управляемая событиями. Все графические приложения управляются событиями.
  • Приложения запускаются в основном цикле, который непрерывно проверяет наличие вновь сгенерированных событий. Если события нет, приложение ждет и ничего не делает.
  • В GTK+ событие-это сообщение от X-сервера . Когда событие достигает виджета, он может отреагировать на это событие, испустив сигнал.
  • Программист GTK+ может подключить к сигналу определенный обратный вызов. Обратный вызов-это функция обработчика, которая реагирует на сигнал.
  • Функция обработчика принимает два параметра: Первый параметр-это объект, который испустил сигнал; в нашем случае это кнопка воспроизведения/паузы. Второй параметр является необязательным, когда можно отправлять события/данные, генерируемые при срабатывании сигнала. Например: тип данных может быть Gdk.EventType .

Вот ссылка, чтобы узнать больше о Событийном программировании .

Соедините кнопки с щелкающими сигналами.

        self.playback_button.connect("clicked", self.toggle_player_playback)
        self.stop_button.connect("clicked", self.stop_player)

Функция toggle_player_playback обрабатывает переключение между опциями воспроизведения/паузы и соответственно устанавливает playback_button изображение.

    def toggle_player_playback(self, widget, data=None):

        """
        Handler for Player's Playback Button (Play/Pause).
        """

        if self.is_player_active == False and self.player_paused == False:
            self.player.play()
            self.playback_button.set_image(self.pause_image)
            self.is_player_active = True

        elif self.is_player_active == True and self.player_paused == True:
            self.player.play()
            self.playback_button.set_image(self.pause_image)
            self.player_paused = False

        elif self.is_player_active == True and self.player_paused == False:
            self.player.pause()
            self.playback_button.set_image(self.play_image)
            self.player_paused = True
        else:
            pass

Функция stop_player останавливает воспроизведение мультимедиа и устанавливает кнопку воспроизведения для воспроизведения изображения.

    def stop_player(self, widget, data=None):
        self.player.stop()
        self.is_player_active = False
        self.playback_button.set_image(self.play_image)

Поверхность Рендеринга носителей

медиаплеер python

Чтобы рисовать на экране, мы используем виджет DrawingArea. Виджет области рисования-это, по сути, X-окно и ничего больше. Это чистый холст, на котором мы можем рисовать все, что захотим. Область рисования создается с помощью вызова ниже.

Размер по умолчанию может быть переопределен, как и для всех виджетов, вызовом set_size_request_ , а это, в свою очередь, также может быть переопределено, если пользователь вручную изменит размер окна, содержащего область рисования.

        self.draw_area = Gtk.DrawingArea()
        self.draw_area.set_size_request(300,300)

Примечание: Этот учебник не охватывает входные сигналы от пользователей GtkDrawingArea. Для захвата событий с устройств ввода, таких как мышь, для этих виджетов нам нужно использовать виджет EventBox .

Подключите область рендеринга к ее сигналу реализации. Сигнал “реализовать” состоит в том, чтобы предпринять любые необходимые действия, когда виджет создается на определенном дисплее. Я расскажу о обработчике _realize позже в этом уроке.

        self.draw_area.connect("realize",self._realized)

Прежде чем обсуждать LibVLC, давайте упакуем виджеты в Gtk.Бокс-виджеты, известные как контейнеры Gtk.

Что такое коробки? Коробки-это невидимые контейнеры, в которые мы можем упаковать наши виджеты. А при упаковке виджетов в горизонтальную коробку объекты вставляются горизонтально слева направо или справа налево в зависимости от того, используется ли Gtk.Box.pack___start() или Gtk.Box.pack_end () .

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

Создайте горизонтально ориентированный контейнер box, в котором между дочерними элементами будет размещено 6 пикселей. Здесь дети-это наши две кнопки управления медиа.

Мы упаковываем вещи с самого начала коробки. Запуск пакета занимает четыре параметра:

  1. GtkWidget будет добавлен в поле.
  2. Boolean expand : TRUE, если новому дочернему элементу должно быть предоставлено дополнительное пространство, выделенное для коробки.
  3. Boolean fill : TRUE, если пространство, предоставленное дочернему элементу опцией expand, фактически выделено дочернему элементу, а не просто заполняет его.
  4. padding : дополнительное пространство в пикселях между этим дочерним элементом и его соседями, превышающее глобальную величину, заданную свойством “spacing”.
        self.hbox = Gtk.Box(spacing=6)
        self.hbox.pack_start(self.playback_button, True, True, 0)
        self.hbox.pack_start(self.stop_button, True, True, 0)

Аналогично, мы создаем вертикально ориентированную коробку и ее дочернее окно верхнего уровня. Затем мы упаковываем сначала поверхность рендеринга, а затем горизонтальную коробку.

        self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.add(self.vbox)
        self.vbox.pack_start(self.draw_area, True, True, 0)
        self.vbox.pack_start(self.hbox, False, False, 0)

Покажите окно рекурсивно и любые дочерние виджеты.

         self.show_all()

Ниже приведен скриншот нашего результирующего графического интерфейса приложения.

медиаплеер python

II. Воспроизведение мультимедиа с помощью фреймворка LibVLC vlc

import vlc

Примечание:

  • Область рисования должна быть реализована до того, как получить ее Гдк.Окно.
  • Мы не можем получить свойство окна напрямую.
  • Нам нужно импортировать GdkX11 для метода xid, потому что окно рендеринга поверхностей является экземпляром Gdk X11.X11Window .
  • GObject.Object -> Gdk.Окно -> Окно Gdk X11.X11
  • Следовательно, импортируйте GdkX11.
gi.require_version('GdkX11', '3.0')
from gi.repository import GdkX11

Как только поверхность рендеринга реализована, ее функция обработчика выполняет следующие операции:

  • Создайте и инициализируйте экземпляр LibVLC и передайте "--no-xlib" в качестве параметра.

  • Создайте пустой объект медиаплеера.

        self.vlcInstance = vlc.Instance("--no-xlib")
        self.player = self.vlcInstance.media_player_new()

Почему это “–нет-xlib” перешел к vlcInstance ?

Как правило, когда несколько потоков используют Xlib (также известный как libX11) одновременно, необходимо вызвать функцию XInitThreads () , так как здесь мы не имеем дела с потоками, использующими xlib. Таким образом, уведомление LibVLC о том, что Xlib не инициализируется для потоков.

  • Получите идентификатор окна окна Media Rendering Surfaces X11 и подключите плеер к окну для вывода мультимедиа.
        win_id = widget.get_window().get_xid()
        self.player.set_xwindow(win_id)
  • Установите MRL (Media Resource Locator — используется LibVLC) для воспроизведения.
        self.player.set_mrl(media_url)

Положив его совсем

import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
gi.require_version('GdkX11', '3.0')
from gi.repository import GdkX11

import vlc

MRL = ""

class ApplicationWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="Python-Vlc Media Player")
        self.player_paused=False
        self.is_player_active = False
        self.connect("destroy",Gtk.main_quit)
           
    def show(self):
        self.show_all()
        
    def setup_objects_and_events(self):
        self.playback_button = Gtk.Button()
        self.stop_button = Gtk.Button()
        
        self.play_image = Gtk.Image.new_from_icon_name(
                "gtk-media-play",
                Gtk.IconSize.MENU
            )
        self.pause_image = Gtk.Image.new_from_icon_name(
                "gtk-media-pause",
                Gtk.IconSize.MENU
            )
        self.stop_image = Gtk.Image.new_from_icon_name(
                "gtk-media-stop",
                Gtk.IconSize.MENU
            )
        
        self.playback_button.set_image(self.play_image)
        self.stop_button.set_image(self.stop_image)
        
        self.playback_button.connect("clicked", self.toggle_player_playback)
        self.stop_button.connect("clicked", self.stop_player)
        
        self.draw_area = Gtk.DrawingArea()
        self.draw_area.set_size_request(300,300)
        
        self.draw_area.connect("realize",self._realized)
        
        self.hbox = Gtk.Box(spacing=6)
        self.hbox.pack_start(self.playback_button, True, True, 0)
        self.hbox.pack_start(self.stop_button, True, True, 0)
        
        self.vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.add(self.vbox)
        self.vbox.pack_start(self.draw_area, True, True, 0)
        self.vbox.pack_start(self.hbox, False, False, 0)
        
    def stop_player(self, widget, data=None):
        self.player.stop()
        self.is_player_active = False
        self.playback_button.set_image(self.play_image)
        
    def toggle_player_playback(self, widget, data=None):

        """
        Handler for Player's Playback Button (Play/Pause).
        """

        if self.is_player_active == False and self.player_paused == False:
            self.player.play()
            self.playback_button.set_image(self.pause_image)
            self.is_player_active = True

        elif self.is_player_active == True and self.player_paused == True:
            self.player.play()
            self.playback_button.set_image(self.pause_image)
            self.player_paused = False

        elif self.is_player_active == True and self.player_paused == False:
            self.player.pause()
            self.playback_button.set_image(self.play_image)
            self.player_paused = True
        else:
            pass
        
    def _realized(self, widget, data=None):
        self.vlcInstance = vlc.Instance("--no-xlib")
        self.player = self.vlcInstance.media_player_new()
        win_id = widget.get_window().get_xid()
        self.player.set_xwindow(win_id)
        self.player.set_mrl(MRL)
        self.player.play()
        self.playback_button.set_image(self.pause_image)
        self.is_player_active = True

if __name__ == '__main__':
    if not sys.argv[1:]:
       print "Exiting \nMust provide the MRL."
       sys.exit(1)
    if len(sys.argv[1:]) == 1:
        MRL = sys.argv[1]
        window = ApplicationWindow()
        window.setup_objects_and_events()
        window.show()
        Gtk.main()
        window.player.stop()
        window.vlcInstance.release()

Gtk.main()

Это цикл обработки GTK+, который работает внутри нашего основного потока приложения.

  • Когда пользователь ничего не делает, GTK+ сидит в основном цикле и ждет ввода. Если пользователь выполняет какое — то действие — скажем, щелчок мыши, – то основной цикл “просыпается” и доставляет событие в GTK+.
  • GTK+ является “потокобезопасным”, но не потокобезопасным — он обеспечивает глобальную блокировку, управляемую gdk_threads_enter() и gdk_threads_leave () , которая защищает все использование GTK+. То есть только один поток может использовать GTK+ в любой момент времени.
  • Вызов Gtk.main_quit() делает основной цикл внутри Gtk.main() return.
  • Таким образом, подключение сигнала “destroy” к Gtk.main_quit() уничтожит окно, а также завершит работу нашего приложения.

Ниже приведен скриншот, показывающий медиаплеер, воспроизводимый в нашем медиаплеере.

медиаплеер python

Похоже, что мы подошли к концу этого урока. Однако это приложение может быть расширено, чтобы добавить больше мультимедийных возможностей и функций пользовательского интерфейса. Поэтому вы можете изучить обе библиотеки, чтобы добавить более надежные функции в свое приложение.

Спасибо! Надеюсь, вам понравился урок. Пожалуйста, оставьте свои вопросы в разделе комментариев ниже.