CLI args parse basic
This commit is contained in:
+84
-47
@@ -3,12 +3,13 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"mxl-player/internal/renderer"
|
"mxl-player/internal/renderer"
|
||||||
"mxl-player/internal/sdl"
|
"mxl-player/internal/sdl"
|
||||||
"mxl-player/internal/source"
|
"mxl-player/internal/source"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@@ -25,7 +26,7 @@ const (
|
|||||||
WIN_HEIGHT int32 = 720
|
WIN_HEIGHT int32 = 720
|
||||||
)
|
)
|
||||||
|
|
||||||
type CliArgs struct {
|
type appArgs struct {
|
||||||
ShowHelp bool
|
ShowHelp bool
|
||||||
Domain string
|
Domain string
|
||||||
VideoFlowId string
|
VideoFlowId string
|
||||||
@@ -40,7 +41,7 @@ type CliArgs struct {
|
|||||||
|
|
||||||
func printCliHelp(fs *pflag.FlagSet) {
|
func printCliHelp(fs *pflag.FlagSet) {
|
||||||
fmt.Printf("%s %s\n", APP_NAME, APP_VER)
|
fmt.Printf("%s %s\n", APP_NAME, APP_VER)
|
||||||
fmt.Println("Usage: mxl-player -d <domain> (-v <uuid> | -a <uuid>) [-f] [-h]...")
|
fmt.Println("Usage: mxl-player -d <domain> (-v <uuid> | -a <uuid>) [-f] [-h]")
|
||||||
fmt.Println(" [-g <gpu-id>] [-p <playback-id>] [--verbose]")
|
fmt.Println(" [-g <gpu-id>] [-p <playback-id>] [--verbose]")
|
||||||
fmt.Println(" or: mxl-player [--list-playback] [--list-gpu]")
|
fmt.Println(" or: mxl-player [--list-playback] [--list-gpu]")
|
||||||
fmt.Println(" or: mxl-player (and set everything in GUI)")
|
fmt.Println(" or: mxl-player (and set everything in GUI)")
|
||||||
@@ -48,50 +49,62 @@ func printCliHelp(fs *pflag.FlagSet) {
|
|||||||
fs.PrintDefaults()
|
fs.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printUsage(w io.Writer) {
|
||||||
|
fmt.Fprintln(w, "Usage: mxl-player -d <domain> (-v <uuid> | -a <uuid>) [-f] [-h]")
|
||||||
|
fmt.Fprintln(w, "Try 'mxl-player -h' for more information.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkMXLargs(args appArgs) {
|
||||||
|
if args.Domain == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "You should provide valid MXL domain and UUID of at least one flow")
|
||||||
|
printUsage(os.Stderr)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Stat(args.Domain)
|
||||||
|
if err != nil || !fi.IsDir() {
|
||||||
|
fmt.Fprintln(os.Stderr, "Invalid MXL domain:", args.Domain)
|
||||||
|
fmt.Fprintln(os.Stderr, "Domain must be a directory in tmpfs")
|
||||||
|
printUsage(os.Stderr)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
if args.VideoFlowId == "" && args.AudioFlowId == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "You must provide at least 1 MXL flow UUID")
|
||||||
|
printUsage(os.Stderr)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// CLI args TODO:
|
|
||||||
// help + sample of good usage
|
|
||||||
// domain (-d, --domain)
|
|
||||||
// video flow UUID (-v, --video)
|
|
||||||
// audio flow UUID (-a, --audio)
|
|
||||||
// list-audio for list audio playback devices (-la, --list-playback)
|
|
||||||
// list-video fpr list video playback devices (-lg, --list-gpu)
|
|
||||||
// gpu-id for GPU selection (-p, --playback-id)
|
|
||||||
// playback-id for playback id selection (-g, --gpu-id)
|
|
||||||
// verbose flag, which turn on logs (-vb,--verbose)
|
|
||||||
//
|
|
||||||
// video: 5fbec3b1-1b0f-417d-9059-8b94a47197ed
|
// video: 5fbec3b1-1b0f-417d-9059-8b94a47197ed
|
||||||
// audio: 5fbec3b1-1b0f-417d-9059-8b94a47197ec
|
// audio: 5fbec3b1-1b0f-417d-9059-8b94a47197ec
|
||||||
|
var args appArgs
|
||||||
var args CliArgs
|
flagSet := pflag.NewFlagSet(APP_NAME, pflag.ContinueOnError)
|
||||||
flagSet := pflag.NewFlagSet(APP_NAME, pflag.ExitOnError)
|
flagSet.Usage = func() { printUsage(os.Stderr) }
|
||||||
flagSet.BoolVarP(&args.ShowHelp, "help", "h", false, "Show help message and exit")
|
flagSet.BoolVarP(&args.ShowHelp, "help", "h", false, "Show help message and exit")
|
||||||
flagSet.StringVarP(&args.Domain, "domain", "d", "", "MXL domain directory")
|
flagSet.StringVarP(&args.Domain, "domain", "d", "", "MXL domain directory")
|
||||||
flagSet.StringVarP(&args.VideoFlowId, "video", "v", "", "Video flow UUID")
|
flagSet.StringVarP(&args.VideoFlowId, "video", "v", "", "Video flow UUID")
|
||||||
flagSet.StringVarP(&args.AudioFlowId, "audio", "a", "", "Audio flow UUID")
|
flagSet.StringVarP(&args.AudioFlowId, "audio", "a", "", "Audio flow UUID")
|
||||||
flagSet.BoolVarP(&args.IsFullscreen, "fullscreen", "f", false, "Run app in fullscreen mode")
|
flagSet.BoolVarP(&args.IsFullscreen, "fullscreen", "f", false, "Run app in fullscreen mode")
|
||||||
flagSet.Uint32VarP(&args.GpuId, "gpu-id", "g", 0, "GPU id")
|
flagSet.Uint32VarP(&args.GpuId, "gpu-id", "g", 0, "GPU id [TODO]")
|
||||||
flagSet.Uint32VarP(&args.PlaybackId, "playback-id", "p", 0, "Playback audio device id")
|
flagSet.Uint32VarP(&args.PlaybackId, "playback-id", "p", 0, "Playback audio device id")
|
||||||
flagSet.BoolVar(&args.IsVerbose, "verbose", false, "Verbose output")
|
flagSet.BoolVar(&args.IsVerbose, "verbose", false, "Verbose output [TODO]")
|
||||||
flagSet.BoolVar(&args.ListAudio, "list-playback", false, "List audio playback devices and exit")
|
flagSet.BoolVar(&args.ListAudio, "list-playback", false, "List audio playback devices and exit")
|
||||||
flagSet.BoolVar(&args.ListGPU, "list-gpu", false, "List GPU's and exit")
|
flagSet.BoolVar(&args.ListGPU, "list-gpu", false, "List GPUs and exit")
|
||||||
pflag.Parse()
|
|
||||||
|
|
||||||
if args.Domain == "" || args.ShowHelp {
|
if err := flagSet.Parse(os.Args[1:]); err != nil {
|
||||||
// TODO. Fix after polishing GUI
|
fmt.Fprintln(os.Stderr, err)
|
||||||
// Cause required/optional will be changed
|
printUsage(os.Stderr)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
if args.ShowHelp {
|
||||||
printCliHelp(flagSet)
|
printCliHelp(flagSet)
|
||||||
}
|
|
||||||
return
|
return
|
||||||
|
|
||||||
var videoFlowId, audioFlowId string
|
|
||||||
mxlDomain := flag.String("d", "/dev/shm/mxl", "MXL domain")
|
|
||||||
mxlVideoFlowID := flag.String("v", videoFlowId, "MXL video flow UUID")
|
|
||||||
mxlAudioFlowID := flag.String("a", audioFlowId, "MXL audio flow UUID")
|
|
||||||
flag.Parse()
|
|
||||||
if *mxlVideoFlowID == "" && *mxlAudioFlowID == "" {
|
|
||||||
log.Fatal("need at least -v <video-flow> or -a <audio-flow>")
|
|
||||||
}
|
}
|
||||||
|
if !args.ListAudio && !args.ListGPU {
|
||||||
|
checkMXLargs(args)
|
||||||
|
}
|
||||||
|
// end of cli args parse
|
||||||
|
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
if err := sdl.Load(); err != nil {
|
if err := sdl.Load(); err != nil {
|
||||||
@@ -102,6 +115,21 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdlAudioDevice := sdl.AudioDeviceDefaultPlayback
|
||||||
|
if args.PlaybackId != 0 {
|
||||||
|
sdlAudioDevice = args.PlaybackId
|
||||||
|
}
|
||||||
|
// List audio playback devices and exit
|
||||||
|
if args.ListAudio {
|
||||||
|
devs := sdl.GetAudioPlaybackDevices()
|
||||||
|
fmt.Println("Available playback audio devices")
|
||||||
|
fmt.Println("id name")
|
||||||
|
for _, d := range devs {
|
||||||
|
fmt.Println(d.ID, d.Name)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
windowHandler := sdl.CreateWindow(fmt.Sprintf("%s %s", APP_NAME, APP_VER), WIN_WIDTH, WIN_HEIGHT, sdl.WindowVulkan|sdl.WindowResizable)
|
windowHandler := sdl.CreateWindow(fmt.Sprintf("%s %s", APP_NAME, APP_VER), WIN_WIDTH, WIN_HEIGHT, sdl.WindowVulkan|sdl.WindowResizable)
|
||||||
if windowHandler == 0 {
|
if windowHandler == 0 {
|
||||||
sdl.Quit()
|
sdl.Quit()
|
||||||
@@ -144,9 +172,15 @@ func main() {
|
|||||||
if err != nil || len(devices) == 0 {
|
if err != nil || len(devices) == 0 {
|
||||||
panic("No Vulkan devices")
|
panic("No Vulkan devices")
|
||||||
}
|
}
|
||||||
for _, pd := range devices {
|
// List GPU's and exit
|
||||||
|
if args.ListGPU {
|
||||||
|
fmt.Println("Available Vulkan physical devices:")
|
||||||
|
fmt.Println("id name (type)")
|
||||||
|
for i, pd := range devices {
|
||||||
info := pd.Info()
|
info := pd.Info()
|
||||||
fmt.Printf("%s (%s)\n", info.Name, info.Type)
|
fmt.Printf("%2d %s (%s)\n", i, info.Name, info.Type)
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
vkPhysDevice := devices[0]
|
vkPhysDevice := devices[0]
|
||||||
|
|
||||||
@@ -194,8 +228,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case *mxlVideoFlowID != "" && *mxlAudioFlowID != "":
|
case args.VideoFlowId != "" && args.AudioFlowId != "":
|
||||||
syncSrc, err = source.OpenSync(*mxlDomain, *mxlVideoFlowID, *mxlAudioFlowID)
|
syncSrc, err = source.OpenSync(args.Domain, args.VideoFlowId, args.AudioFlowId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("sync source: %v", err)
|
log.Fatalf("sync source: %v", err)
|
||||||
}
|
}
|
||||||
@@ -204,7 +238,7 @@ func main() {
|
|||||||
if audioBatch == 0 {
|
if audioBatch == 0 {
|
||||||
audioBatch = 1
|
audioBatch = 1
|
||||||
}
|
}
|
||||||
audioStream = sdl.OpenAudioDeviceStream(sdl.AudioDeviceDefaultPlayback, sdl.AudioSpec{
|
audioStream = sdl.OpenAudioDeviceStream(sdlAudioDevice, sdl.AudioSpec{
|
||||||
Format: sdl.AudioF32,
|
Format: sdl.AudioF32,
|
||||||
Channels: int32(aChans),
|
Channels: int32(aChans),
|
||||||
Freq: int32(syncSrc.AudioRate().Num / syncSrc.AudioRate().Den),
|
Freq: int32(syncSrc.AudioRate().Num / syncSrc.AudioRate().Den),
|
||||||
@@ -215,16 +249,16 @@ func main() {
|
|||||||
sdl.ResumeAudioStreamDevice(audioStream)
|
sdl.ResumeAudioStreamDevice(audioStream)
|
||||||
fmt.Printf("sync: video %dx%d audio %dch batch=%d\n",
|
fmt.Printf("sync: video %dx%d audio %dch batch=%d\n",
|
||||||
syncSrc.Width(), syncSrc.Height(), aChans, audioBatch)
|
syncSrc.Width(), syncSrc.Height(), aChans, audioBatch)
|
||||||
|
case args.VideoFlowId != "":
|
||||||
|
|
||||||
case *mxlVideoFlowID != "":
|
videoSrc, err = source.Open(args.Domain, args.VideoFlowId)
|
||||||
videoSrc, err = source.Open(*mxlDomain, *mxlVideoFlowID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("source: %v", err)
|
log.Fatalf("source: %v", err)
|
||||||
}
|
}
|
||||||
fmt.Printf("video: %dx%d stride=%d\n", videoSrc.Width(), videoSrc.Height(), videoSrc.Stride())
|
fmt.Printf("video: %dx%d stride=%d\n", videoSrc.Width(), videoSrc.Height(), videoSrc.Stride())
|
||||||
|
|
||||||
default:
|
default:
|
||||||
audioSrc, err = source.OpenAudio(*mxlDomain, *mxlAudioFlowID)
|
audioSrc, err = source.OpenAudio(args.Domain, args.AudioFlowId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("audio source: %v", err)
|
log.Fatalf("audio source: %v", err)
|
||||||
}
|
}
|
||||||
@@ -233,7 +267,7 @@ func main() {
|
|||||||
if audioBatch == 0 {
|
if audioBatch == 0 {
|
||||||
audioBatch = 1
|
audioBatch = 1
|
||||||
}
|
}
|
||||||
audioStream = sdl.OpenAudioDeviceStream(sdl.AudioDeviceDefaultPlayback, sdl.AudioSpec{
|
audioStream = sdl.OpenAudioDeviceStream(sdlAudioDevice, sdl.AudioSpec{
|
||||||
Format: sdl.AudioF32,
|
Format: sdl.AudioF32,
|
||||||
Channels: int32(aChans),
|
Channels: int32(aChans),
|
||||||
Freq: int32(audioSrc.Rate().Num / audioSrc.Rate().Den),
|
Freq: int32(audioSrc.Rate().Num / audioSrc.Rate().Den),
|
||||||
@@ -261,7 +295,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var r *renderer.Renderer
|
var r *renderer.Renderer
|
||||||
if *mxlVideoFlowID != "" {
|
if args.VideoFlowId != "" {
|
||||||
var w, h, stride uint32
|
var w, h, stride uint32
|
||||||
if syncSrc != nil {
|
if syncSrc != nil {
|
||||||
w, h, stride = syncSrc.Width(), syncSrc.Height(), syncSrc.Stride()
|
w, h, stride = syncSrc.Width(), syncSrc.Height(), syncSrc.Stride()
|
||||||
@@ -309,7 +343,7 @@ func main() {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
if syncSrc != nil {
|
if syncSrc != nil {
|
||||||
s, e := source.OpenSync(*mxlDomain, *mxlVideoFlowID, *mxlAudioFlowID)
|
s, e := source.OpenSync(args.Domain, args.VideoFlowId, args.AudioFlowId)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
if r != nil {
|
if r != nil {
|
||||||
newSize := vk.DeviceSize(s.Stride()) * vk.DeviceSize(s.Height())
|
newSize := vk.DeviceSize(s.Stride()) * vk.DeviceSize(s.Height())
|
||||||
@@ -324,7 +358,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
log.Printf("source: reopen retry: %v", e)
|
log.Printf("source: reopen retry: %v", e)
|
||||||
} else if videoSrc != nil {
|
} else if videoSrc != nil {
|
||||||
s, e := source.Open(*mxlDomain, *mxlVideoFlowID)
|
s, e := source.Open(args.Domain, args.VideoFlowId)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
if r != nil {
|
if r != nil {
|
||||||
newSize := vk.DeviceSize(s.Stride()) * vk.DeviceSize(s.Height())
|
newSize := vk.DeviceSize(s.Stride()) * vk.DeviceSize(s.Height())
|
||||||
@@ -339,7 +373,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
log.Printf("source: reopen retry: %v", e)
|
log.Printf("source: reopen retry: %v", e)
|
||||||
} else if audioSrc != nil {
|
} else if audioSrc != nil {
|
||||||
s, e := source.OpenAudio(*mxlDomain, *mxlAudioFlowID)
|
s, e := source.OpenAudio(args.Domain, args.AudioFlowId)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
audioSrc = s
|
audioSrc = s
|
||||||
return nil
|
return nil
|
||||||
@@ -477,7 +511,10 @@ func main() {
|
|||||||
running := true
|
running := true
|
||||||
resized := false
|
resized := false
|
||||||
granted := false
|
granted := false
|
||||||
fullscreen := false
|
fullscreen := args.IsFullscreen
|
||||||
|
if fullscreen {
|
||||||
|
sdl.SetWindowFullscreen(windowHandler, true)
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
lastIndex uint64
|
lastIndex uint64
|
||||||
dropped uint64
|
dropped uint64
|
||||||
|
|||||||
Reference in New Issue
Block a user