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
+65
View File
@@ -0,0 +1,65 @@
package media
import (
"encoding/json"
"ffmpeg-gui/internal/ffmpeg"
"fmt"
)
// StreamInfo holds information about a single stream.
type StreamInfo struct {
Index int `json:"index"`
CodecType string `json:"codec_type"`
CodecName string `json:"codec_name"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
Duration string `json:"duration,omitempty"`
BitRate string `json:"bit_rate,omitempty"`
FPS string `json:"r_frame_rate,omitempty"`
Language string `json:"tags>language,omitempty"`
}
// FormatInfo holds container format information.
type FormatInfo struct {
Filename string `json:"filename"`
Format string `json:"format_name"`
Duration string `json:"duration,omitempty"`
Size string `json:"size,omitempty"`
BitRate string `json:"bit_rate,omitempty"`
}
// MediaInfo is the top-level ffprobe result.
type MediaInfo struct {
Streams []StreamInfo `json:"streams"`
Format FormatInfo `json:"format"`
}
// GetInfo runs ffprobe and returns parsed media information.
func GetInfo(exec *ffmpeg.Executor, inputFile string) (*MediaInfo, error) {
out, err := exec.Probe(
"-v", "quiet",
"-print_format", "json",
"-show_format",
"-show_streams",
inputFile,
)
if err != nil {
return nil, fmt.Errorf("ffprobe: %w (output: %s)", err, out)
}
var info MediaInfo
if err := json.Unmarshal([]byte(out), &info); err != nil {
return nil, fmt.Errorf("parse ffprobe json: %w", err)
}
return &info, nil
}
// GetDurationSeconds returns the duration in seconds as a float64.
func (mi *MediaInfo) GetDurationSeconds() float64 {
if mi.Format.Duration == "" {
return 0
}
var secs float64
fmt.Sscanf(mi.Format.Duration, "%f", &secs)
return secs
}