1

私のプログラムでは、PyGObject/PyGI と GStreamer を使用して、GUI でビデオを表示します。ビデオは a で表示されるため、 -signal-handlerGtk.DrawingAreaでそのウィンドウ ハンドルを取得する必要があります。realizeLinux では、次を使用してそのハンドルを取得します。

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

しかし、どうすれば Windows でハンドルを取得できますか?

window.handleインターネットで検索しましたが、PyGI を使用して動作しないPyGtk を使用した例のみが見つかりました。

GStreamer のドキュメントには、マクロを使用してハンドルを取得する例が記載されています。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)
4

2 に答える 2

1

やっと手に入れました。「ウィンドウ ハンドル」の問題に対処するために、Marwin Schmitt による回避策/ハックを使用します (こちらを参照)。

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

しかし、「同期メッセージ」ハンドラが呼び出されないという問題もありました。すべてのビデオ シンクが埋め込みビデオをサポートしているわけではないことがわかりました。こちら を参照してください。たとえば、d3dvideosinkは埋め込みビデオをサポートしていますが、仮想マシンで Windows を実行していて、3D ハードウェア アクセラレーションが有効になっていてもおそらく動作しませんでした。仮想化されていない Windows で同じコードを実行すると、「sync-message」ハンドラーへのコールバックが発生し、以前に取得したウィンドウ ハンドルを設定できます。

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 での再生は問題なく動作するようになりました。

于 2015-08-05T13:34:10.967 に答える
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    
于 2015-07-22T06:47:29.253 に答える