Rewrite FFmpeg devices and add support ALSA for Linux
This commit is contained in:
@@ -3,24 +3,41 @@ package device
|
|||||||
import (
|
import (
|
||||||
"github.com/AlexxIT/go2rtc/internal/api"
|
"github.com/AlexxIT/go2rtc/internal/api"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||||
|
"net/url"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://trac.ffmpeg.org/wiki/Capture/Webcam
|
func queryToInput(query url.Values) string {
|
||||||
const deviceInputPrefix = "-f avfoundation"
|
video := query.Get("video")
|
||||||
|
audio := query.Get("audio")
|
||||||
|
|
||||||
func deviceInputSuffix(video, audio string) string {
|
if video == "" && audio == "" {
|
||||||
switch {
|
return ""
|
||||||
case video != "" && audio != "":
|
|
||||||
return `"` + video + `:` + audio + `"`
|
|
||||||
case video != "":
|
|
||||||
return `"` + video + `"`
|
|
||||||
case audio != "":
|
|
||||||
return `":` + audio + `"`
|
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
|
// https://ffmpeg.org/ffmpeg-devices.html#avfoundation
|
||||||
|
input := "-f avfoundation"
|
||||||
|
|
||||||
|
if video != "" {
|
||||||
|
video = indexToItem(videos, video)
|
||||||
|
|
||||||
|
for key, value := range query {
|
||||||
|
switch key {
|
||||||
|
case "resolution":
|
||||||
|
input += " -video_size " + value[0]
|
||||||
|
case "pixel_format", "framerate", "video_size", "capture_cursor", "capture_mouse_clicks", "capture_raw_data":
|
||||||
|
input += " -" + key + " " + value[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if audio != "" {
|
||||||
|
audio = indexToItem(audios, audio)
|
||||||
|
}
|
||||||
|
|
||||||
|
return input + ` -i "` + video + `:` + audio + `"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDevices() {
|
func initDevices() {
|
||||||
|
|||||||
@@ -3,19 +3,36 @@ package device
|
|||||||
import (
|
import (
|
||||||
"github.com/AlexxIT/go2rtc/internal/api"
|
"github.com/AlexxIT/go2rtc/internal/api"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://trac.ffmpeg.org/wiki/Capture/Webcam
|
func queryToInput(query url.Values) string {
|
||||||
const deviceInputPrefix = "-f v4l2"
|
if video := query.Get("video"); video != "" {
|
||||||
|
// https://ffmpeg.org/ffmpeg-devices.html#video4linux2_002c-v4l2
|
||||||
|
input := "-f v4l2"
|
||||||
|
|
||||||
func deviceInputSuffix(video, audio string) string {
|
for key, value := range query {
|
||||||
if video != "" {
|
switch key {
|
||||||
return video
|
case "resolution":
|
||||||
|
input += " -video_size " + value[0]
|
||||||
|
case "video_size", "pixel_format", "input_format", "framerate", "use_libv4l2":
|
||||||
|
input += " -" + key + " " + value[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return input + " -i " + indexToItem(videos, video)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if audio := query.Get("audio"); audio != "" {
|
||||||
|
input := "-f alsa"
|
||||||
|
|
||||||
|
return input + " -i " + indexToItem(audios, audio)
|
||||||
|
}
|
||||||
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,4 +74,15 @@ func initDevices() {
|
|||||||
streams = append(streams, stream)
|
streams = append(streams, stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = exec.Command(Bin, "-f", "alsa", "-i", "default", "-t", "1", "-f", "null", "-").Run()
|
||||||
|
if err == nil {
|
||||||
|
stream := api.Stream{
|
||||||
|
Name: "ALSA default",
|
||||||
|
URL: "ffmpeg:device?audio=default#audio=opus",
|
||||||
|
}
|
||||||
|
|
||||||
|
audios = append(audios, "default")
|
||||||
|
streams = append(streams, stream)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,58 @@ package device
|
|||||||
import (
|
import (
|
||||||
"github.com/AlexxIT/go2rtc/internal/api"
|
"github.com/AlexxIT/go2rtc/internal/api"
|
||||||
"github.com/AlexxIT/go2rtc/pkg/core"
|
"github.com/AlexxIT/go2rtc/pkg/core"
|
||||||
|
"net/url"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// https://trac.ffmpeg.org/wiki/DirectShow
|
func queryToInput(query url.Values) string {
|
||||||
const deviceInputPrefix = "-f dshow"
|
video := query.Get("video")
|
||||||
|
audio := query.Get("audio")
|
||||||
|
|
||||||
|
if video == "" && audio == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://ffmpeg.org/ffmpeg-devices.html#dshow
|
||||||
|
input := "-f dshow"
|
||||||
|
|
||||||
|
if video != "" {
|
||||||
|
video = indexToItem(videos, video)
|
||||||
|
|
||||||
|
for key, value := range query {
|
||||||
|
switch key {
|
||||||
|
case "resolution":
|
||||||
|
input += " -video_size " + value[0]
|
||||||
|
case "video_size", "framerate", "pixel_format":
|
||||||
|
input += " -" + key + " " + value[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if audio != "" {
|
||||||
|
audio = indexToItem(audios, audio)
|
||||||
|
|
||||||
|
for key, value := range query {
|
||||||
|
switch key {
|
||||||
|
case "sample_rate", "sample_size", "channels", "audio_buffer_size":
|
||||||
|
input += " -" + key + " " + value[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if video != "" {
|
||||||
|
input += ` -i video="` + video + `"`
|
||||||
|
|
||||||
|
if audio != "" {
|
||||||
|
input += `:audio="` + audio + `"`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
input += ` -i audio="` + audio + `"`
|
||||||
|
}
|
||||||
|
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
func deviceInputSuffix(video, audio string) string {
|
func deviceInputSuffix(video, audio string) string {
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package device
|
package device
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"github.com/AlexxIT/go2rtc/internal/api"
|
"github.com/AlexxIT/go2rtc/internal/api"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -16,45 +17,23 @@ func Init(bin string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetInput(src string) (string, error) {
|
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:])
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
runonce.Do(initDevices)
|
runonce.Do(initDevices)
|
||||||
|
|
||||||
input := deviceInputPrefix
|
if input := queryToInput(query); input != "" {
|
||||||
|
return input, nil
|
||||||
var video, audio string
|
|
||||||
|
|
||||||
if i := strings.IndexByte(src, '?'); i > 0 {
|
|
||||||
query, err := url.ParseQuery(src[i+1:])
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
for key, value := range query {
|
|
||||||
switch key {
|
|
||||||
case "video":
|
|
||||||
video = value[0]
|
|
||||||
case "audio":
|
|
||||||
audio = value[0]
|
|
||||||
case "resolution":
|
|
||||||
input += " -video_size " + value[0]
|
|
||||||
default: // "input_format", "framerate", "video_size"
|
|
||||||
input += " -" + key + " " + value[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if video != "" {
|
return "", errors.New("wrong query: " + src)
|
||||||
if i, err := strconv.Atoi(video); err == nil && i < len(videos) {
|
|
||||||
video = videos[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if audio != "" {
|
|
||||||
if i, err := strconv.Atoi(audio); err == nil && i < len(audios) {
|
|
||||||
audio = audios[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
input += " -i " + deviceInputSuffix(video, audio)
|
|
||||||
|
|
||||||
return input, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var Bin string
|
var Bin string
|
||||||
@@ -68,3 +47,10 @@ func apiDevices(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
api.ResponseStreams(w, streams)
|
api.ResponseStreams(w, streams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func indexToItem(items []string, index string) string {
|
||||||
|
if i, err := strconv.Atoi(index); err == nil && i < len(items) {
|
||||||
|
return items[i]
|
||||||
|
}
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user