获取PyGI中的窗口句柄
问题描述:
在我的程序中,我使用PyGObject/PyGI和GStreamer在我的GUI中显示视频。该视频显示在Gtk.DrawingArea
中,因此我需要在realize
-信号处理程序中获取它的窗口句柄。在Linux上,我得到该处理使用:获取PyGI中的窗口句柄
drawing_area.get_property('window').get_xid()
但是,我如何得到Windows上的句柄?
我在网上搜索,但发现只使用PyGtk使用window.handle
,它不能使用PyGI的例子。
GStreamer文档提供了一个使用GDK_WINDOW_HWND
宏获取句柄的example。该宏使用AFAIK gdk_win32_drawable_get_handle
。但如何使用PyGI在Python中完成?
更新15-07-28:新增(简体)代码
我仍然没有得到视频播放在Windows上运行。
问题1:我无法在_on_video_realize()中获得窗口句柄。
问题2:方法_on_player_sync_message()永远不会被调用。
class MultimediaPlayer:
def __init__(self):
# ... some init stuff ...
self._drawing_area.connect('realize', self._on_video_realize)
self._drawing_area.connect('unrealize', self._on_video_unrealize)
# GStreamer setup
# ---------------
self._player = Gst.ElementFactory.make('playbin', 'MultimediaPlayer')
bus = self._player.get_bus()
bus.add_signal_watch()
bus.connect('message', self._on_player_message)
bus.enable_sync_message_emission()
bus.connect('sync-message::element', self._on_player_sync_message)
def _on_video_realize(self, widget):
print('----------> _on_video_realize')
# The xid must be retrieved first in GUI-thread and before
# playing pipeline.
if sys.platform == "win32":
self._drawing_area.get_property('window').ensure_native()
# -------------------------------------------------------------
# TODO [PROBLEM 1] How to get handle here?
# self._drawing_area.GetHandle() does not exist!
# -------------------------------------------------------------
else:
self._wnd_hnd = (self._drawing_area.get_property('window')
.get_xid())
def _on_video_unrealize(self, widget):
self._player.set_state(Gst.State.NULL)
def _on_player_message(self, bus, message):
# ... handle some messages here ...
def _on_player_sync_message(self, bus, message):
# ---------------------------------------------------------------------
# TODO [PROBLEM 2] This method is never called on Windows after opening
# a video_file! But on Linux it is!
# ---------------------------------------------------------------------
print('----------> _on_player_sync_message')
if message.get_structure() is None:
return True
if message.get_structure().get_name() == "prepare-window-handle":
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_window_handle(self._wnd_hnd)
def play(self):
self._player.set_state(Gst.State.PLAYING)
def stop(self):
self._player.set_state(Gst.State.NULL)
def set_file(self, file):
# ...
self._player.set_property('uri', "file:///" + file)
答
我终于得到它。为了解决“窗口句柄” -issue我用的解决方法/通过的MarWin施密特(see here)黑客:
def _on_video_realize(self, widget):
# The window handle must be retrieved first in GUI-thread and before
# playing pipeline.
video_window = self._drawing_area.get_property('window')
if sys.platform == "win32":
if not video_window.ensure_native():
print("Error - video playback requires a native window")
ctypes.pythonapi.PyCapsule_GetPointer.restype = ctypes.c_void_p
ctypes.pythonapi.PyCapsule_GetPointer.argtypes = [ctypes.py_object]
drawingarea_gpointer = ctypes.pythonapi.PyCapsule_GetPointer(video_window.__gpointer__, None)
gdkdll = ctypes.CDLL ("libgdk-3-0.dll")
self._video_window_handle = gdkdll.gdk_win32_window_get_handle(drawingarea_gpointer)
else:
self._video_window_handle = video_window.get_xid()
但也有问题,那-handler从未被称为“同步消息”。我发现并非所有视频接收器都支持嵌入式视频,see here。例如,d3dvideosink
确实支持嵌入式视频,但我在虚拟机中运行Windows,即使激活了3D硬件加速,它也可能不起作用。在非虚拟化的Windows上运行相同的代码导致回调至“同步消息” -handler在先前所获取的窗口句柄,可以设置:
def _on_player_sync_message(self, bus, message):
if message.get_structure() is None:
return
if not GstVideo.is_video_overlay_prepare_window_handle_message(message):
return
imagesink = message.src
imagesink.set_property("force-aspect-ratio", True)
imagesink.set_window_handle(self._video_window_handle)
播放Windows上现在工作得很好。
答
你试过:
def OnSyncMessage(self, bus, msg):
if msg.get_structure() is None:
return True
message_name = msg.get_structure().get_name()
if message_name == 'prepare-window-handle':
imagesink = msg.src
imagesink.set_property('force-aspect-ratio', True)
imagesink.set_window_handle(self.DrawingArea.GetHandle())
return True
感谢您的回复。我注意到我的'OnSyncMessage'方法永远不会在Windows上调用。而我的'DrawingArea'不包含一个名为'GetHandle'的方法。我编辑了我的问题,并添加了一些代码。也许你注意到了一个错误。 :) – Biggie 2015-07-28 18:12:50
对不起,没有东西跳出来对我。 – 2015-07-29 06:55:57