在PyGI中获取窗口句柄 [英] Get the window handle in PyGI

查看:113
本文介绍了在PyGI中获取窗口句柄的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my program I use PyGObject/PyGI and GStreamer to show a video in my GUI. The video is shown in a Gtk.DrawingArea and therefore I need to get it's window-handle in the realize-signal-handler. On Linux I get that handle using:

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

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

But how do I get the handle on Windows?

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

I searched on the internet but found only examples for PyGtk using window.handle which does not work using PyGI.

GStreamer文档提供了

The GStreamer documentation provides an example which uses the GDK_WINDOW_HWND macro to get the handle. This macro uses AFAIK gdk_win32_drawable_get_handle. But how to do it in Python using PyGI?

更新15-07-28:添加(简化)代码
我仍然无法在Windows上播放视频.
问题1:我无法在_on_video_realize()中获得窗口句柄.
问题2:从未调用_on_player_sync_message()方法.

Update 15-07-28: Added (simplified) code
I'm still not getting video playback to work on Windows.
Problem 1: I cannot get the window handle in _on_video_realize().
Problem 2: The method _on_player_sync_message() is never called.

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)

推荐答案

我终于明白了.为了解决窗口句柄"问题,我使用了Marwin Schmitt(

I finally got it. To address the "window handle"-issue I use the workaround/hack by Marwin Schmitt (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()

但是还有一个问题,就是从来没有调用过"sync-message"处理程序.我发现并非所有视频接收器都支持嵌入式视频,

But there was also the problem, that the "sync-message"-handler was never called. I found out that not all video sinks support embedded video, see here. For example the d3dvideosink does support embedded video, but I was running Windows in a virtual machine and even though 3D hardware acceleration was activated it probably didn't work. Running the same code on a non-virtualized Windows leads to a callback to the "sync-message"-handler where the previously fetched window-handle can be set:

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上正常播放了.

Playback on Windows works fine now.

这篇关于在PyGI中获取窗口句柄的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆