在Fyne.io中集成mpv进行媒体播放

引言

在我的一个项目中,,我需要在Fyne编写的GUI中播放视频。然而Fyne这个框架原生并不支持视频播放,所以我引入了MPV作为视频解码与播放的库。

为了将MPV的输出集成到Fyne的GUI中,我可以通过设置MPV的wid选项来控制。在Windows上,这个WID就是Windows
handle id (HWND)。 在Linux中,这个ID通常为X11的window id。

然而,Fyne同样不支持直接获取window id。为了实现这个功能,我们需要对Fyne进行一些修改,具体修改如下。

修改Fyne源码

首先,在window_windows.go文件中,添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
func (w *window) Wid() uintptr {
w.viewLock.RLock()
defer w.viewLock.RUnlock()

if w.closing {
return 0
}
if (w.viewport == nil) {
return uintptr(0)
}
return uintptr(w.viewport.GetWin32Window())
}

接下来,在window_linux.go文件中,添加以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
func (w *window) Wid() uintptr {
w.viewLock.RLock()
defer w.viewLock.RUnlock()

if w.closing {
return 0
}
if (w.viewport == nil) {
return uintptr(0)
}
return uintptr(w.viewport.GetX11Window())
}

测试代码

以下是使用修改后的Fyne源码并结合MPV库的测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package main

import (
"fmt"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/app"
"fyne.io/fyne/v2/theme"
"github.com/aynakeya/go-mpv"
)

type WindowHandleMagic interface {
Wid() uintptr
}

// need to apply patch first
func GetWindowHandle(window fyne.Window) uintptr {
x, ok := window.(WindowHandleMagic)
if ok {
return x.Wid()
}
return 0
}

func main() {
a := app.NewWithID("io.fyne.mpvdemo")
a.SetIcon(theme.FyneLogo())
window := a.NewWindow("Fyne MPV Player Demo")
var libmpv *mpv.Mpv = nil
window.Resize(fyne.NewSize(1080, 720))
go func() {
wid := GetWindowHandle(window)
for wid == 0 {
wid = GetWindowHandle(window)
}
fmt.Printf("got windows handle %d\n", wid)
libmpv = mpv.Create()
err := libmpv.Initialize()
if err != nil {
panic(err)
}
fmt.Println(libmpv.SetOptionString("wid", fmt.Sprintf("%d", wid)))
fmt.Println(libmpv.Command([]string{"loadfile", "/home/aynakeya/Videos/ymca.mp4"}))
}()
window.ShowAndRun()
if libmpv != nil {
libmpv.Destroy()
}
}

效果图

img

Reference

https://github.com/fyne-io/fyne/issues/449#issuecomment-1546820151
AynaLivePlayer