150 lines
3.3 KiB
Go
150 lines
3.3 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"git.leaktechnologies.dev/stu/VT_Player/player/mpvembed"
|
|
|
|
"github.com/gotk3/gotk3/gdk"
|
|
"github.com/gotk3/gotk3/gtk"
|
|
)
|
|
|
|
// simple GTK + mpv embedded player demo (single pane).
|
|
|
|
func main() {
|
|
flag.Parse()
|
|
gtk.Init(nil)
|
|
|
|
win, err := gtk.WindowNew(gtk.WINDOW_TOPLEVEL)
|
|
if err != nil {
|
|
log.Fatalf("window: %v", err)
|
|
}
|
|
win.SetTitle("VT Player (GTK/mpv)")
|
|
win.SetDefaultSize(1280, 720)
|
|
|
|
grid, _ := gtk.GridNew()
|
|
grid.SetColumnHomogeneous(true)
|
|
grid.SetRowHomogeneous(false)
|
|
win.Add(grid)
|
|
|
|
// Drawing area for mpv
|
|
da, _ := gtk.DrawingAreaNew()
|
|
da.SetHexpand(true)
|
|
da.SetVexpand(true)
|
|
grid.Attach(da, 0, 1, 4, 1)
|
|
|
|
// Controls
|
|
openBtn, _ := gtk.ButtonNewWithLabel("Open...")
|
|
playBtn, _ := gtk.ButtonNewWithLabel("Play")
|
|
pauseBtn, _ := gtk.ButtonNewWithLabel("Pause")
|
|
seekStartBtn, _ := gtk.ButtonNewWithLabel("<< Start")
|
|
grid.Attach(openBtn, 0, 0, 1, 1)
|
|
grid.Attach(playBtn, 1, 0, 1, 1)
|
|
grid.Attach(pauseBtn, 2, 0, 1, 1)
|
|
grid.Attach(seekStartBtn, 3, 0, 1, 1)
|
|
|
|
mpv, err := mpvembed.New()
|
|
if err != nil {
|
|
log.Fatalf("mpv: %v", err)
|
|
}
|
|
defer mpv.Destroy()
|
|
|
|
var duration float64
|
|
|
|
da.Connect("realize", func() {
|
|
w := da.GetWindow()
|
|
if w == nil {
|
|
log.Println("no window yet")
|
|
return
|
|
}
|
|
// Bind native window ID
|
|
if xid := getWindowID(w); xid != 0 {
|
|
_ = mpv.SetWID(xid)
|
|
}
|
|
// Set options and init
|
|
_ = mpv.SetOptionString("pause", "yes")
|
|
if err := mpv.Initialize(); err != nil {
|
|
log.Fatalf("mpv init: %v", err)
|
|
}
|
|
})
|
|
|
|
openBtn.Connect("clicked", func() {
|
|
dlg, _ := gtk.FileChooserDialogNewWith1Button("Open Video", win, gtk.FILE_CHOOSER_ACTION_OPEN, "Open", gtk.RESPONSE_ACCEPT)
|
|
if resp := dlg.Run(); resp == int(gtk.RESPONSE_ACCEPT) {
|
|
filename := dlg.GetFilename()
|
|
if filename != "" {
|
|
loadFile(mpv, filename, &duration)
|
|
}
|
|
}
|
|
dlg.Destroy()
|
|
})
|
|
|
|
playBtn.Connect("clicked", func() {
|
|
_ = mpv.SetPropertyBool("pause", false)
|
|
})
|
|
pauseBtn.Connect("clicked", func() {
|
|
_ = mpv.SetPropertyBool("pause", true)
|
|
})
|
|
seekStartBtn.Connect("clicked", func() {
|
|
_ = mpv.Command("seek", "0", "absolute", "exact")
|
|
})
|
|
|
|
// Progress poll
|
|
go func() {
|
|
t := time.NewTicker(250 * time.Millisecond)
|
|
defer t.Stop()
|
|
for range t.C {
|
|
pos, err := mpv.GetPropertyDouble("time-pos")
|
|
if err == nil && duration > 0 {
|
|
fmt.Printf("\r%.1f / %.1f", pos, duration)
|
|
}
|
|
}
|
|
}()
|
|
|
|
win.Connect("destroy", func() {
|
|
gtk.MainQuit()
|
|
})
|
|
|
|
win.ShowAll()
|
|
gtk.Main()
|
|
}
|
|
|
|
func loadFile(mpv *mpvembed.Client, path string, duration *float64) {
|
|
base := filepath.Base(path)
|
|
fmt.Printf("\nLoading: %s\n", base)
|
|
if err := mpv.Command("loadfile", path, "replace"); err != nil {
|
|
log.Printf("loadfile: %v", err)
|
|
}
|
|
if d, err := mpv.GetPropertyDouble("duration"); err == nil {
|
|
*duration = d
|
|
}
|
|
_ = mpv.SetPropertyBool("pause", false)
|
|
}
|
|
|
|
// getWindowID returns the native window handle (XID on X11, HWND on Windows).
|
|
func getWindowID(w *gdk.Window) uint64 {
|
|
// X11
|
|
if xid := gdkWindowGetXID(w); xid != 0 {
|
|
return xid
|
|
}
|
|
// TODO: add Windows handle if needed.
|
|
return 0
|
|
}
|
|
|
|
// gdkWindowGetXID extracts the XID from a GDK window when running on X11.
|
|
func gdkWindowGetXID(w *gdk.Window) uint64 {
|
|
type xidGetter interface {
|
|
GetXID() uint
|
|
}
|
|
if xw, ok := w.(xidGetter); ok {
|
|
return uint64(xw.GetXID())
|
|
}
|
|
return 0
|
|
}
|
|
|