diff --git a/cmd/ffmpeg/device_darwin.go b/cmd/ffmpeg/device/device_darwin.go similarity index 92% rename from cmd/ffmpeg/device_darwin.go rename to cmd/ffmpeg/device/device_darwin.go index f6216e89..78ea152f 100644 --- a/cmd/ffmpeg/device_darwin.go +++ b/cmd/ffmpeg/device/device_darwin.go @@ -1,4 +1,4 @@ -package ffmpeg +package device import ( "bytes" @@ -26,7 +26,7 @@ func deviceInputSuffix(videoIdx, audioIdx int) string { func loadMedias() { cmd := exec.Command( - tpl["bin"], "-hide_banner", "-list_devices", "true", "-f", "avfoundation", "-i", "dummy", + Bin, "-hide_banner", "-list_devices", "true", "-f", "avfoundation", "-i", "dummy", ) var buf bytes.Buffer diff --git a/cmd/ffmpeg/device_linux.go b/cmd/ffmpeg/device/device_linux.go similarity index 68% rename from cmd/ffmpeg/device_linux.go rename to cmd/ffmpeg/device/device_linux.go index c02407d9..9c17c7b6 100644 --- a/cmd/ffmpeg/device_linux.go +++ b/cmd/ffmpeg/device/device_linux.go @@ -1,9 +1,10 @@ -package ffmpeg +package device import ( + "bytes" "github.com/AlexxIT/go2rtc/pkg/streamer" - "github.com/rs/zerolog/log" "io/ioutil" + "os/exec" "strings" ) @@ -24,12 +25,25 @@ func loadMedias() { log.Trace().Msg("[ffmpeg] " + file.Name()) if strings.HasPrefix(file.Name(), streamer.KindVideo) { media := loadMedia(streamer.KindVideo, "/dev/"+file.Name()) - medias = append(medias, media) + if media != nil { + medias = append(medias, media) + } } } } func loadMedia(kind, name string) *streamer.Media { + cmd := exec.Command( + Bin, "-hide_banner", "-f", "v4l2", "-list_formats", "all", "-i", name, + ) + var buf bytes.Buffer + cmd.Stderr = &buf + _ = cmd.Run() + + if !bytes.Contains(buf.Bytes(), []byte("Raw")) { + return nil + } + return &streamer.Media{ Kind: kind, Title: name, } diff --git a/cmd/ffmpeg/device_windows.go b/cmd/ffmpeg/device/device_windows.go similarity index 93% rename from cmd/ffmpeg/device_windows.go rename to cmd/ffmpeg/device/device_windows.go index 78b134af..9b7c0190 100644 --- a/cmd/ffmpeg/device_windows.go +++ b/cmd/ffmpeg/device/device_windows.go @@ -1,4 +1,4 @@ -package ffmpeg +package device import ( "bytes" @@ -26,7 +26,7 @@ func deviceInputSuffix(videoIdx, audioIdx int) string { func loadMedias() { cmd := exec.Command( - tpl["bin"], "-hide_banner", "-list_devices", "true", "-f", "dshow", "-i", "", + Bin, "-hide_banner", "-list_devices", "true", "-f", "dshow", "-i", "", ) var buf bytes.Buffer diff --git a/cmd/ffmpeg/devices.go b/cmd/ffmpeg/device/devices.go similarity index 77% rename from cmd/ffmpeg/devices.go rename to cmd/ffmpeg/device/devices.go index e622ff0e..aefa3dc6 100644 --- a/cmd/ffmpeg/devices.go +++ b/cmd/ffmpeg/device/devices.go @@ -1,16 +1,24 @@ -package ffmpeg +package device import ( "encoding/json" + "github.com/AlexxIT/go2rtc/cmd/api" + "github.com/AlexxIT/go2rtc/cmd/app" "github.com/AlexxIT/go2rtc/pkg/streamer" - "github.com/rs/zerolog/log" + "github.com/rs/zerolog" "net/http" "net/url" "strconv" "strings" ) -func getDevice(src string) (string, error) { +func Init() { + log = app.GetLogger("exec") + + api.HandleFunc("/api/devices", handle) +} + +func GetInput(src string) (string, error) { if medias == nil { loadMedias() } @@ -42,6 +50,8 @@ func getDevice(src string) (string, error) { return input, nil } +var Bin string +var log zerolog.Logger var medias []*streamer.Media func findMedia(kind string, index int) *streamer.Media { @@ -57,7 +67,7 @@ func findMedia(kind string, index int) *streamer.Media { return nil } -func handleDevices(w http.ResponseWriter, r *http.Request) { +func handle(w http.ResponseWriter, r *http.Request) { if medias == nil { loadMedias() } diff --git a/cmd/ffmpeg/ffmpeg.go b/cmd/ffmpeg/ffmpeg.go index 167ba9a9..032d7801 100644 --- a/cmd/ffmpeg/ffmpeg.go +++ b/cmd/ffmpeg/ffmpeg.go @@ -1,9 +1,9 @@ package ffmpeg import ( - "github.com/AlexxIT/go2rtc/cmd/api" "github.com/AlexxIT/go2rtc/cmd/app" "github.com/AlexxIT/go2rtc/cmd/exec" + "github.com/AlexxIT/go2rtc/cmd/ffmpeg/device" "github.com/AlexxIT/go2rtc/cmd/streams" "github.com/AlexxIT/go2rtc/pkg/streamer" "net/url" @@ -21,9 +21,9 @@ func Init() { "bin": "ffmpeg", // inputs - "link": "-i {input}", - "rtsp": "-fflags nobuffer -flags low_delay -rtsp_transport tcp -i {input}", "file": "-re -stream_loop -1 -i {input}", + "http": "-i {input}", + "rtsp": "-fflags nobuffer -flags low_delay -rtsp_transport tcp -i {input}", // output "out": "-rtsp_transport tcp -f rtsp {output}", @@ -49,7 +49,7 @@ func Init() { app.LoadConfig(&cfg) - tpl = cfg.Mod + tpl := cfg.Mod streams.HandleFunc("ffmpeg", func(s string) (streamer.Producer, error) { s = s[7:] // remove `ffmpeg:` @@ -60,20 +60,29 @@ func Init() { s = s[:i] } - var template string - switch { - case strings.HasPrefix(s, "rtsp"): - template = tpl["rtsp"] - case strings.HasPrefix(s, "device"): - template, _ = getDevice(s) - case strings.Contains(s, "://"): - template = tpl["link"] - default: - template = tpl["file"] + var input string + if i := strings.IndexByte(s, ':'); i > 0 { + switch s[:i] { + case "http", "https": + input = strings.Replace(tpl["http"], "{input}", s, 1) + case "rtsp", "rtsps": + input = strings.Replace(tpl["rtsp"], "{input}", s, 1) + } } - s = "exec:" + tpl["bin"] + " -hide_banner " + - strings.Replace(template, "{input}", s, 1) + if input == "" { + if strings.HasPrefix(s, "device?") { + var err error + input, err = device.GetInput(s) + if err != nil { + return nil, err + } + } else { + input = strings.Replace(tpl["file"], "{input}", s, 1) + } + } + + s = "exec:" + tpl["bin"] + " -hide_banner " + input if query != nil { for _, raw := range query["raw"] { @@ -114,11 +123,10 @@ func Init() { return exec.Handle(s) }) - api.HandleFunc("/api/devices", handleDevices) + device.Bin = cfg.Mod["bin"] + device.Init() } -var tpl map[string]string - func parseQuery(s string) map[string][]string { query := map[string][]string{} for _, key := range strings.Split(s, "#") {