python - 如何在 Gtk 对话框中显示视频?

标签 python python-3.5 gtk3 gstreamer-1.0

我想在对话框中显示视频。

因此,我创建了一个 Gst.DrawingArea 和一个 Gst.Pipeline,其中包含一个 Gst.Element “playbin”。

我创建了一个小示例,它打开一个带有按钮的窗口。 如果单击该按钮,则会打开对话框并播放视频。 但我只听到视频的音频。

在另一个只有一个窗口和一个 DrawingArea 的示例中,它工作正常。

是否可以在 Gtk.Dialog 中显示视频?

我使用的是 Python 3.5.2。

编辑:

#!/usr/bin/python3

from os import path

import gi
gi.require_version('Gst', '1.0')
gi.require_version('Gtk', '3.0')
gi.require_version('GdkX11', '3.0')
gi.require_version('GstVideo', '1.0')
from gi.repository import Gst, Gtk, GLib, GdkX11, GstVideo

from gi.repository import GObject


GObject.threads_init()
Gst.init(None)
filename = "/path/to/movie.avi"
uri = 'file://' + filename


class DialogExample(Gtk.Dialog):

def __init__(self, parent):
    Gtk.Dialog.__init__(self, "My Dialog", parent, 0,
        (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
         Gtk.STOCK_OK, Gtk.ResponseType.OK))

    self.drawingarea = Gtk.DrawingArea.new()

    self.drawingarea.connect('draw', self.on_draw)
    #self.drawingarea.connect('realize', self.on_realize)
    self.drawingarea.connect('unrealize', self.on_unrealize)
    self.drawingarea.set_size_request(800, 600)
    self.set_default_size(1000, 800)

    self.btn_Play = Gtk.Button.new_with_label("Play")
    self.btn_Play.connect('clicked', self.on_click)

    box = self.get_content_area()
    box.add(self.drawingarea)
    box.add(self.btn_Play)

    # Create GStreamer pipeline
    self.pipeline = Gst.Pipeline()

    # Create bus to get events from GStreamer pipeline
    self.bus = self.pipeline.get_bus()
    self.bus.add_signal_watch()
    self.bus.connect('message::eos', self.on_eos)
    self.bus.connect('message::error', self.on_error)

    # This is needed to make the video output in our DrawingArea:
    self.bus.enable_sync_message_emission()
    self.bus.connect('sync-message::element', self.on_sync_message)

    # Create GStreamer elements
    self.playbin = Gst.ElementFactory.make('playbin', None)

    # Add playbin to the pipeline
    self.pipeline.add(self.playbin)

    # Set properties
    self.playbin.set_property('uri', uri)

    self.show_all()


def on_click(self, button):
    if self.playbin.get_state(0).state == Gst.State.PAUSED:
        self.pipeline.set_state(Gst.State.PLAYING)
        button.set_label("Stop")
    else:
        self.pipeline.set_state(Gst.State.PAUSED)
        button.set_label("Play")

def on_realize(self, widget, data=None):
    print("on_relaize")

    window = widget.get_window()
    self.xid = window.get_xid()
    self.playbin.set_window_handle(self.xid)


def on_draw(self, widget, cr):
    print("ondraw", self.playbin.get_state(0).state)
    if self.playbin.get_state(0).state < Gst.State.PAUSED:
        allocation = widget.get_allocation()

        cr.set_source_rgb(0, 0, 0)
        cr.rectangle(0, 0, allocation.width, allocation.height)
        cr.fill()

    self.on_realize(widget)


def on_unrealize(self, widget, data=None):
    # to prevent racing conditions when closing the window while playing
    self.playbin.set_state(Gst.State.NULL)
    self.pipeline.set_state(Gst.State.NULL)

def on_sync_message(self, bus, msg):
    if msg.get_structure().get_name() == 'prepare-window-handle':
        print('prepare-window-handle')

        print('on_sync', self.xid)

        print(msg)
        print(msg.src)


def on_eos(self, bus, msg):
    print('on_eos(): seeking to start of video')
    self.pipeline.seek_simple(
        Gst.Format.TIME,
        Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
        0
    )

def on_error(self, bus, msg):
    print('on_error():', msg.parse_error())



class DialogWindow(Gtk.Window):

def __init__(self):
    Gtk.Window.__init__(self, title="Dialog Example")

    self.set_border_width(6)

    button = Gtk.Button("Open dialog")
    button.connect("clicked", self.on_button_clicked)

    self.add(button)



def on_button_clicked(self, widget):
    dialog = DialogExample(self)


    response = dialog.run()

    if response == Gtk.ResponseType.OK:
        print("The OK button was clicked")
    elif response == Gtk.ResponseType.CANCEL:
        print("The Cancel button was clicked")

    dialog.destroy()


win = DialogWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

编辑2: UI after I pressed the play button

最佳答案

也许您的drawingarea没有调用on_realize方法... 我有同样的错误并决定强制它,在我的代码中保持这种方式:

def on_realize(self, widget):
    print("on realize")
    window = widget.get_window()
    window_handle = window.get_xid()
    self.player.set_window_handle(window_handle)

def on_draw(self, widget, cr):
    print("ondraw",self.player.get_state(0).state)
    if self.player.get_state(0).state < Gst.State.PAUSED:
        allocation = widget.get_allocation()

        cr.set_source_rgb(0, 0, 0)
        cr.rectangle(0, 0, allocation.width, allocation.height)
        cr.fill()

    self.on_realize(widget)

这样,当ondraw完成时,自动调用on_realize方法

我尝试了你的代码,经过下面注释中描述的修改后,它变成了这样

#!/usr/bin/python3

from os import path

import gi
gi.require_version('Gst', '1.0')
gi.require_version('Gtk', '3.0')
gi.require_version('GdkX11', '3.0')
gi.require_version('GstVideo', '1.0')
from gi.repository import Gst, Gtk, GLib, GdkX11, GstVideo

from gi.repository import GObject


GObject.threads_init()
Gst.init(None)
filename = "/home/eduardo/Downloads/tears_of_steel_1080p.webm"
uri = 'file://' + filename


class DialogExample(Gtk.Dialog):

    def __init__(self, parent):
        Gtk.Dialog.__init__(self, "My Dialog", parent, 0,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_OK, Gtk.ResponseType.OK))

        self.drawingarea = Gtk.DrawingArea.new()

        self.drawingarea.connect('draw', self.on_draw)
        self.drawingarea.connect('realize', self.on_realize)
        self.drawingarea.connect('unrealize', self.on_unrealize)
        self.drawingarea.set_size_request(800, 600)
        self.set_default_size(1000, 800)

        self.btn_Play = Gtk.Button.new_with_label("Play")
        self.btn_Play.connect('clicked', self.on_click)

        box = self.get_content_area()
        box.add(self.drawingarea)
        box.add(self.btn_Play)

        # Create GStreamer pipeline
        self.pipeline = Gst.Pipeline()

        # Create bus to get events from GStreamer pipeline
        self.bus = self.pipeline.get_bus()
        self.bus.add_signal_watch()
        self.bus.connect('message::eos', self.on_eos)
        self.bus.connect('message::error', self.on_error)

        # This is needed to make the video output in our DrawingArea:
        self.bus.enable_sync_message_emission()
        self.bus.connect('sync-message::element', self.on_sync_message)

        # Create GStreamer elements
        self.playbin = Gst.ElementFactory.make('playbin', None)

        # Add playbin to the pipeline
        self.pipeline.add(self.playbin)

        # Set properties
        self.playbin.set_property('uri', uri)

        self.show_all()


    def on_click(self, button):
        if self.playbin.get_state(0).state != Gst.State.PAUSED:
            self.pipeline.set_state(Gst.State.PLAYING)
            button.set_label("Stop")
        else:
            self.pipeline.set_state(Gst.State.PAUSED)
            button.set_label("Play")

    def on_realize(self, widget, data=None):
        print("on_relaize")

        window = widget.get_window()
        self.xid = window.get_xid()


    def on_draw(self, widget, cr):
        print("ondraw", self.playbin.get_state(0).state)
        if self.playbin.get_state(0).state < Gst.State.PAUSED:
            allocation = widget.get_allocation()

            cr.set_source_rgb(0, 0, 0)
            cr.rectangle(0, 0, allocation.width, allocation.height)
            cr.fill()

#       self.on_realize(widget)


    def on_unrealize(self, widget, data=None):
        # to prevent racing conditions when closing the window while playing
        self.playbin.set_state(Gst.State.NULL)
        self.pipeline.set_state(Gst.State.NULL)

    def on_sync_message(self, bus, msg):
        if msg.get_structure().get_name() == 'prepare-window-handle':
            print('prepare-window-handle')

            print('on_sync', self.xid)
            self.playbin.set_window_handle(self.xid)

            print(msg)
            print(msg.src)


    def on_eos(self, bus, msg):
        print('on_eos(): seeking to start of video')
        self.pipeline.seek_simple(
            Gst.Format.TIME,
            Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT,
            0
        )

    def on_error(self, bus, msg):
        print('on_error():', msg.parse_error())



class DialogWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="Dialog Example")

        self.set_border_width(6)

        button = Gtk.Button("Open dialog")
        button.connect("clicked", self.on_button_clicked)

        self.add(button)



    def on_button_clicked(self, widget):
        dialog = DialogExample(self)


        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            print("The OK button was clicked")
        elif response == Gtk.ResponseType.CANCEL:
            print("The Cancel button was clicked")

        dialog.destroy()


win = DialogWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

关于python - 如何在 Gtk 对话框中显示视频?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40563216/

相关文章:

python - 将 pandas 数据框切成具有一定列数的行?

python - 如何在 Python 中使用 JSON 从文件的特定列表中检索特定字符串

python - 创建一个使用列表上的键返回分数的程序

database - 我们可以使用 cx_oracle 库 python 连接到任何版本的 oracle 吗?

python - 自定义 numpy 类型导致 numpy.mean 崩溃

python - 为什么Class property.setter不是方法重载的情况?

python - 我应该如何在 __init__ 中定义一个依赖协程的变量?

c - GTK+ 中基于模板的 UI 的优点是什么

python - pyGtk3 对话必须有 parent 吗?如果是这样,您如何从脚本中调用它们?

css - GTK 3 如何在 css 文件中选择笔记本的事件选项卡