feat: FFmpeg GUI desktop application

Wails v2 + Vue3 + Go project with:
- Encode/Remux/Subtitle burn with hardware acceleration
- Real-time progress with ffmpeg stderr parsing (\r delimiter handling)
- Task queue with cancel support
- Per-task log viewer with color-coded output
- Custom frameless window with resize support
- Dark/light theme toggle
- Hardware encoder detection (NVENC/QSV/AMF)
This commit is contained in:
sansen
2026-07-29 02:17:57 +08:00
parent 51b768a2ba
commit 79f5fb8ac3
36 changed files with 5216 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
//go:build !windows
package platform
// EnableResizeBorder is a no-op on non-Windows platforms.
func EnableResizeBorder() {}
+70
View File
@@ -0,0 +1,70 @@
//go:build windows
package platform
import (
"os"
"syscall"
"unsafe"
)
var (
user32 = syscall.NewLazyDLL("user32.dll")
kernel32 = syscall.NewLazyDLL("kernel32.dll")
setWindowLong = user32.NewProc("SetWindowLongW")
getWindowLong = user32.NewProc("GetWindowLongW")
setWindowPos = user32.NewProc("SetWindowPos")
enumWindows = user32.NewProc("EnumWindows")
getWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
getCurrentProcessId = kernel32.NewProc("GetCurrentProcessId")
)
const (
GWL_STYLE = ^uintptr(15) // -16
WS_THICKFRAME = 0x00040000
WS_MAXIMIZEBOX = 0x00010000
WS_MINIMIZEBOX = 0x00020000
SWP_FRAMECHANGED = 0x0020
SWP_NOMOVE = 0x0002
SWP_NOSIZE = 0x0001
SWP_NOZORDER = 0x0004
SWP_NOACTIVATE = 0x0010
)
var mainHwnd uintptr
// EnableResizeBorder re-adds the WS_THICKFRAME style to
// the frameless Wails window so it can be resized from edges.
func EnableResizeBorder() {
pid, _, _ := getCurrentProcessId.Call()
// Find our main window by enumerating top-level windows
cb := syscall.NewCallback(func(hwnd uintptr, lparam uintptr) uintptr {
var wpid uintptr
getWindowThreadProcessId.Call(hwnd, uintptr(unsafe.Pointer(&wpid)))
if wpid == pid {
// Check if it's a visible owned window (not a child/message-only)
style, _, _ := getWindowLong.Call(hwnd, GWL_STYLE)
if style&0x10000000 != 0 && style&0x40000000 == 0 { // WS_VISIBLE && !WS_CHILD
mainHwnd = hwnd
return 0 // stop enumeration
}
}
return 1 // continue
})
enumWindows.Call(cb, 0)
if mainHwnd == 0 {
return
}
style, _, _ := getWindowLong.Call(mainHwnd, GWL_STYLE)
newStyle := style | WS_THICKFRAME | WS_MAXIMIZEBOX | WS_MINIMIZEBOX
setWindowLong.Call(mainHwnd, GWL_STYLE, newStyle)
setWindowPos.Call(mainHwnd, 0, 0, 0, 0, 0,
SWP_FRAMECHANGED|SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE)
// Log for debugging
os.Stdout.WriteString("[platform] WS_THICKFRAME enabled on frameless window\n")
}