我想在对话框中显示视频。
因此,我创建了一个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()
答案 0 :(得分:2)
也许您的 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)
这样,当它完成提取时,自动调用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()
答案 1 :(得分:0)
这是使用gstreamer的gtksink
的另一种方法。如果正在运行“讨厌的”合成器,这甚至应该可以工作(正如问问者提到使用Cinnamon的Linux Mint中的问题):
#!/usr/bin/env python3
import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Gst", "1.0")
from gi.repository import Gtk, Gst
import os, sys
Gst.init(None)
Gst.init_check(None)
class PlayerWidget(Gtk.Box):
""" This is the gtksink widget """
def __init__(self, parent):
super().__init__()
self.parent = parent
self.player = Gst.ElementFactory.make("playbin")
self.connect('realize', self.on_realize)
def on_realize(self, widget):
playerFactory = self.player.get_factory()
gtksink = playerFactory.make('gtksink')
self.player.set_property("video-sink", gtksink)
self.pack_start(gtksink.props.widget, True, True, 0)
gtksink.props.widget.show()
class VideoDialog(Gtk.Dialog):
def __init__(self, parent, filename):
Gtk.Dialog.__init__(self, "VideoDialog", parent, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.filename = filename
self.__setupUi()
def __setupUi(self):
self.set_default_size(800, 400)
self.playerWidget = PlayerWidget(parent=self)
self.playerWidget.set_size_request(800, 450)
self.player = self.playerWidget.player
self.player.set_property("uri", self.filename)
self.btnPlay = Gtk.Button(label="Play")
self.btnPlay.connect("clicked", self.on_btnPlay_clicked)
self.hboxBtn01 = Gtk.Box()
self.hboxBtn01.add(self.btnPlay)
self.vbox_intern = self.get_content_area()
self.vbox_intern.add(self.playerWidget)
self.vbox_intern.add(self.hboxBtn01)
self.show_all()
def on_btnPlay_clicked(self, widget):
playerState = self.player.get_state(Gst.SECOND).state
if playerState <= Gst.State.PAUSED:
self.player.set_state(Gst.State.PLAYING)
self.btnPlay.set_label("Pause")
elif playerState is Gst.State.PLAYING:
self.player.set_state(Gst.State.PAUSED)
self.btnPlay.set_label("Play")
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Open VideoDialog")
self.filename = "https://www.freedesktop.org/software/gstreamer-sdk" + \
"/data/media/sintel_trailer-480p.webm"
self.set_border_width(40)
self.set_default_size(200, 110)
button = Gtk.Button("Don't push the button!")
button.connect("clicked", self.on_button_clicked)
self.add(button)
def on_button_clicked(self, widget):
videoDialog = VideoDialog(self, self.filename)
videoDialog.set_transient_for(self)
videoDialog.set_modal(True)
if Gtk.ResponseType.OK == videoDialog.run():
print("Response: OK")
else:
print("Response: Cancel")
videoDialog.player.set_state(Gst.State.NULL)
videoDialog.destroy()
win = MainWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
编辑:
在基于debian的发行版中,gstreamer的gtksink似乎不在它所属的软件包中(即gst-plugins-good)。在Debian 9上,它是gst-plugins-bad
(?)的一部分。在Ubuntu 18.04上,gst-inspect1.0 gtksink
声称它是gst-plugins-good
的一部分,但不是。在gstreamer1.0-gtk3
中。因此,您将必须安装...?
答案 2 :(得分:0)
vishal-mote,我刚刚添加了文件选择器对话框,并将uri / url编码添加到file://,以便gtk应用程序播放选定的视频。
#!/usr/bin/env python3
gi.require_version("Gtk", "3.0")
gi.require_version("Gst", "1.0")
from gi.repository import Gtk, Gst
from urllib.parse import urlparse
from urllib.parse import quote
import os, sys
Gst.init(None)
Gst.init_check(None)
class PlayerWidget(Gtk.Box):
""" This is the gtksink widget """
def __init__(self, parent):
super().__init__()
self.parent = parent
self.player = Gst.ElementFactory.make("playbin")
self.connect('realize', self.on_realize)
def on_realize(self, widget):
playerFactory = self.player.get_factory()
gtksink = playerFactory.make('gtksink')
self.player.set_property("video-sink", gtksink)
self.pack_start(gtksink.props.widget, True, True, 0)
gtksink.props.widget.show()
class VideoDialog(Gtk.Dialog):
def __init__(self, parent, filename):
Gtk.Dialog.__init__(self, "VideoDialog", parent, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.filename = filename
self.__setupUi()
def __setupUi(self):
self.set_default_size(800, 400)
self.playerWidget = PlayerWidget(parent=self)
self.playerWidget.set_size_request(800, 450)
self.player = self.playerWidget.player
self.player.set_property("uri", self.filename)
self.btnPlay = Gtk.Button(label="Play")
self.btnPlay.connect("clicked", self.on_btnPlay_clicked)
self.hboxBtn01 = Gtk.Box()
self.hboxBtn01.add(self.btnPlay)
self.vbox_intern = self.get_content_area()
self.vbox_intern.add(self.playerWidget)
self.vbox_intern.add(self.hboxBtn01)
self.show_all()
def on_btnPlay_clicked(self, widget):
playerState = self.player.get_state(Gst.SECOND).state
if playerState <= Gst.State.PAUSED:
self.player.set_state(Gst.State.PLAYING)
self.btnPlay.set_label("Pause")
elif playerState is Gst.State.PLAYING:
self.player.set_state(Gst.State.PAUSED)
self.btnPlay.set_label("Play")
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Open VideoDialog")
self.filename = "https://www.freedesktop.org/software/gstreamer-sdk" + \
"/data/media/sintel_trailer-480p.webm"
self.set_border_width(40)
self.set_default_size(200, 110)
button = Gtk.Button("Choose File!")
button.connect("clicked", self.on_file_clicked)
self.add(button)
#uncomment below to start the player as if button is pressed
#self.on_button_clicked(Gtk.Button)
def on_file_clicked(self, widget):
dialog = Gtk.FileChooserDialog(
title="Please choose a file", parent=self, action=Gtk.FileChooserAction.OPEN
)
dialog.add_buttons(
Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN,
Gtk.ResponseType.OK,
)
self.add_filters(dialog)
response = dialog.run()
if response == Gtk.ResponseType.OK:
print("Open clicked")
print("File selected: " + dialog.get_filename())
self.filename = quote(dialog.get_filename())
#encode URI to file://<path+filename>
self.filename = "file://"+self.filename
print(self.filename)
# when the file is selected cose the file dialog
dialog.destroy()
self.on_button_clicked(Gtk.Button)
elif response == Gtk.ResponseType.CANCEL:
print("Cancel clicked")
dialog.destroy()
def add_filters(self, dialog):
filter_video = Gtk.FileFilter()
filter_video.set_name("Video File")
filter_video.add_mime_type("video/*")
dialog.add_filter(filter_video)
filter_any = Gtk.FileFilter()
filter_any.set_name("Any files")
filter_any.add_pattern("*")
dialog.add_filter(filter_any)
def on_button_clicked(self, widget):
videoDialog = VideoDialog(self, self.filename)
videoDialog.set_transient_for(self)
videoDialog.set_modal(True)
if Gtk.ResponseType.OK == videoDialog.run():
print("Response: OK")
else:
print("Response: Cancel")
videoDialog.player.set_state(Gst.State.NULL)
videoDialog.destroy()
win = MainWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()