繁体   English   中英

使Python中的GStreamer视频/音频流畅循环

[英]Making GStreamer video/audio in Python smooth and loop

我正在尝试使用 GStreamer 平滑地循环播放 MPEG-4 文件。 我想播放视频和音频(如果有的话)并循环播放。 我的应用程序使用 GTK 作为 UI。

现在我遇到三个问题:

  1. Raspberry Pi 4 上的视频播放不稳定/不稳定,我正在运行它。 断断续续/生涩,我的意思是每隔约 1-2 秒,播放会冻结几分之一秒。 在 VLC 应用程序中播放同一视频时,它很流畅。
  2. 不播放音频。 同样,在 VLC 中播放时,音频如预期的那样存在。 据我了解, playbin元素会自动播放音频和视频。
  3. 到达视频结尾时,最后一帧会冻结 1-2 秒,然后视频会再次从第一帧开始播放。

我目前有以下代码。


video_player.py:

#!/usr/bin/python3
import os
import gi

gi.require_version("Gst", "1.0")
gi.require_version("Gtk", "3.0")
gi.require_version("GstVideo", "1.0")
from gi.repository import Gst, Gtk, GstVideo


class VideoPlayer(Gtk.DrawingArea):
    def __init__(self, video_uri: str, loop: bool):
        super().__init__()
        self.__loop = loop
        self.__video_uri = "file:///" + os.path.abspath(video_uri)
        self.__xid = None

        Gst.init(None)
        self.connect("realize", self.__on_realize)
        self.set_size_request(1920, 1080) # Hardcoded for this example

        self.__playbin = Gst.ElementFactory.make("playbin", "player")
        self.__bus = self.__playbin.get_bus()
        self.__bus.add_signal_watch()
        self.__bus.connect("message::eos", self.__on_video_end)
        self.__bus.enable_sync_message_emission()
        self.__bus.connect("sync-message::element", self.__on_sync_message)
        self.__playbin.set_property("uri", self.__video_uri)

    def __on_realize(self, widget: Gtk.Window, data=None) -> None:
        window = widget.get_window()
        self.__xid = window.get_xid()

    def __on_sync_message(self, bus: Gst.Bus, message: Gst.Message) -> None:
        if message.get_structure().get_name() == "prepare-window-handle":
            image_sink = message.src
            image_sink.set_property("force-aspect-ratio", True)
            image_sink.set_window_handle(self.__xid)

    def __on_video_end(self, bus: Gst.Bus, message: Gst.Message) -> None:
        if self.__loop:
            self.__playbin.set_state(Gst.State.NULL)
            self.__playbin.set_state(Gst.State.PLAYING)

    def play(self) -> None:
        if self.__playbin.get_state(0).state != Gst.State.PLAYING:
            self.__playbin.set_state(Gst.State.PLAYING)

主要文件:

#!/usr/bin/python3
from video_player import VideoPlayer
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk

window = Gtk.Window()
video_player = VideoPlayer("test_video.mp4", loop=True)

window.add(video_player)
window.fullscreen()
window.show_all()

video_player.play()

Gtk.main()

这个答案提供了一个使用 VLC 的例子; 问题的作者接受了这一点(请参阅评论)-Raspberry Pi 4 和其他类似 SOC 上的 GStreamer 通常会出现滞后和软解决方案,如果不开始修改 Gstreamer 库,可能不会帮助 OP。

请注意,该代码的灵感来自https://www.codementor.io/@princerapa/python-media-player-vlc-gtk-favehuy2b ,但已根据您的需要进行了修改。

进行视频循环所需的更改(上述链接中未提供)是将参数“--input-repeat=-1”传递给 vlcinstance。

安装依赖项(假设您已经安装了 gtk)

pip install python-vlc

你的代码:

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 = ""  # File to play
WIDTH = 300
HEIGHT = 300

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(WIDTH,HEIGHT)
        
        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", "--input-repeat=-1")
        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()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM