diff --git a/internal/ffmpeg/device/devices.go b/internal/ffmpeg/device/devices.go index a51abd64..69b13444 100644 --- a/internal/ffmpeg/device/devices.go +++ b/internal/ffmpeg/device/devices.go @@ -1,11 +1,9 @@ package device import ( - "errors" "net/http" "net/url" "strconv" - "strings" "sync" "github.com/AlexxIT/go2rtc/internal/api" @@ -17,24 +15,15 @@ func Init(bin string) { api.HandleFunc("api/ffmpeg/devices", apiDevices) } -func GetInput(src string) (string, error) { - i := strings.IndexByte(src, '?') - if i < 0 { - return "", errors.New("empty query: " + src) - } - - query, err := url.ParseQuery(src[i+1:]) +func GetInput(src string) string { + query, err := url.ParseQuery(src) if err != nil { - return "", err + return "" } runonce.Do(initDevices) - if input := queryToInput(query); input != "" { - return input, nil - } - - return "", errors.New("wrong query: " + src) + return queryToInput(query) } var Bin string diff --git a/internal/ffmpeg/ffmpeg.go b/internal/ffmpeg/ffmpeg.go index 63b4a39d..c5587e3c 100644 --- a/internal/ffmpeg/ffmpeg.go +++ b/internal/ffmpeg/ffmpeg.go @@ -189,21 +189,21 @@ func parseArgs(s string) *ffmpeg.Args { s += "?video&audio" } args.Input = inputTemplate("rtsp", s, query) - } else if strings.HasPrefix(s, "device?") { - var err error - args.Input, err = device.GetInput(s) - if err != nil { - return nil - } - } else if strings.HasPrefix(s, "virtual?") { - var err error - if args.Input, err = virtual.GetInput(s[8:]); err != nil { - return nil + } else if i = strings.Index(s, "?"); i > 0 { + switch s[:i] { + case "device": + args.Input = device.GetInput(s[i+1:]) + case "virtual": + args.Input = virtual.GetInput(s[i+1:]) } } else { args.Input = inputTemplate("file", s, query) } + if args.Input == "" { + return nil + } + if query["async"] != nil { args.Input = "-use_wallclock_as_timestamps 1 -async 1 " + args.Input } diff --git a/internal/ffmpeg/virtual/virtual.go b/internal/ffmpeg/virtual/virtual.go index 2e1dd9bd..f738c41f 100644 --- a/internal/ffmpeg/virtual/virtual.go +++ b/internal/ffmpeg/virtual/virtual.go @@ -4,56 +4,59 @@ import ( "net/url" ) -func GetInput(src string) (string, error) { +func GetInput(src string) string { query, err := url.ParseQuery(src) if err != nil { - return "", err + return "" } - // set defaults (using Add instead of Set) - query.Add("video", "testsrc") - query.Add("size", "1920x1080") - query.Add("decimals", "2") + input := "-re" - // https://ffmpeg.org/ffmpeg-filters.html - video := query.Get("video") - input := "-re -f lavfi -i " + video + for _, video := range query["video"] { + // https://ffmpeg.org/ffmpeg-filters.html + sep := "=" // first separator - sep := "=" // first separator - for key, values := range query { - value := values[0] - - // https://ffmpeg.org/ffmpeg-utils.html#video-size-syntax - switch key { - case "color", "rate", "duration", "sar": - case "size": - switch value { - case "720": - value = "1280x720" // crf=1 -> 12 Mbps - case "1080": - value = "1920x1080" // crf=1 -> 25 Mbps - case "2K": - value = "2560x1440" // crf=1 -> 43 Mbps - case "4K": - value = "3840x2160" // crf=1 -> 103 Mbps - case "8K": - value = "7680x4230" // https://reolink.com/blog/8k-resolution/ - } - case "decimals": - if video != "testsrc" { - continue - } - default: - continue + if video == "" { + video = "testsrc=decimals=2" // default video + sep = ":" } - input += sep + key + "=" + value - sep = ":" // next separator + input += " -f lavfi -i " + video + + // set defaults (using Add instead of Set) + query.Add("size", "1920x1080") + + for key, values := range query { + value := values[0] + + // https://ffmpeg.org/ffmpeg-utils.html#video-size-syntax + switch key { + case "color", "rate", "duration", "sar", "decimals": + case "size": + switch value { + case "720": + value = "1280x720" // crf=1 -> 12 Mbps + case "1080": + value = "1920x1080" // crf=1 -> 25 Mbps + case "2K": + value = "2560x1440" // crf=1 -> 43 Mbps + case "4K": + value = "3840x2160" // crf=1 -> 103 Mbps + case "8K": + value = "7680x4230" // https://reolink.com/blog/8k-resolution/ + } + default: + continue + } + + input += sep + key + "=" + value + sep = ":" // next separator + } + + if s := query.Get("format"); s != "" { + input += ",format=" + s + } } - if s := query.Get("format"); s != "" { - input += ",format=" + s - } - - return input, nil + return input }