【问题标题】:Get the window handle in PyGI在 PyGI 中获取窗口句柄
【发布时间】:2014-09-13 13:07:56
【问题描述】:

在我的程序中,我使用 PyGObject/PyGI 和 GStreamer 在我的 GUI 中显示视频。该视频显示在Gtk.DrawingArea 中,因此我需要在realize-signal-handler 中获取它的窗口句柄。在 Linux 上,我使用:

drawing_area.get_property('window').get_xid()

但是如何在 Windows 上获取句柄?

我在互联网上进行了搜索,但仅找到了使用 window.handle 的 PyGtk 示例,而使用 PyGI 则无法使用。

GStreamer 文档提供了一个example,它使用GDK_WINDOW_HWND 宏来获取句柄。此宏使用 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)

【问题讨论】:

    标签: python gstreamer gtk3 pygobject python-gstreamer


    【解决方案1】:

    我终于明白了。为了解决“窗口句柄”问题,我使用了 Marwin Schmitt (see here) 的解决方法/hack:

    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()
    

    但也存在问题,“同步消息”处理程序从未被调用过。我发现并非所有视频接收器都支持嵌入式视频see here。例如,d3dvideosink 确实支持嵌入式视频,但我在虚拟机中运行 Windows,即使激活了 3D 硬件加速,它也可能无法正常工作。在非虚拟化 Windows 上运行相同的代码会导致对“同步消息”处理程序的回调,其中可以设置先前获取的窗口句柄:

    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 上播放。

    【讨论】:

      【解决方案2】:

      你试过了吗:

      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 的方法。我在上面编辑了我的问题并添加了一些代码。也许你注意到了一个错误。 :)
      • 对不起,我什么都没有。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-22
      • 2010-11-30
      • 1970-01-01
      • 2011-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多