2014-09-13 155 views
1

在我的程序中,我使用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) 

回答

1

我终于得到它。为了解决“窗口句柄” -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上现在工作得很好。

0

你试过:

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  
+0

感谢您的回复。我注意到我的'OnSyncMessage'方法永远不会在Windows上调用。而我的'DrawingArea'不包含一个名为'GetHandle'的方法。我编辑了我的问题,并添加了一些代码。也许你注意到了一个错误。 :) – Biggie 2015-07-28 18:12:50

+0

对不起,没有东西跳出来对我。 – 2015-07-29 06:55:57