From f6936f7ceed5173771a05365745c5a1af1911f99 Mon Sep 17 00:00:00 2001 From: "Galindo, Alex" Date: Thu, 6 Jul 2023 10:25:09 +0200 Subject: [PATCH 1/5] Allow add Input param without codecs changes. Correct the Input Template to delete the 'input' parameter to allow set the copy codecs option, otherwise the '-vn -an' codecs option is selected. --- internal/ffmpeg/ffmpeg.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/internal/ffmpeg/ffmpeg.go b/internal/ffmpeg/ffmpeg.go index d185a5f6..bb4886ab 100644 --- a/internal/ffmpeg/ffmpeg.go +++ b/internal/ffmpeg/ffmpeg.go @@ -2,6 +2,9 @@ package ffmpeg import ( "errors" + "net/url" + "strings" + "github.com/AlexxIT/go2rtc/internal/app" "github.com/AlexxIT/go2rtc/internal/ffmpeg/device" "github.com/AlexxIT/go2rtc/internal/ffmpeg/hardware" @@ -9,8 +12,6 @@ import ( "github.com/AlexxIT/go2rtc/internal/streams" "github.com/AlexxIT/go2rtc/pkg/core" "github.com/AlexxIT/go2rtc/pkg/ffmpeg" - "net/url" - "strings" ) func Init() { @@ -103,8 +104,9 @@ var defaults = map[string]string{ } // inputTemplate - select input template from YAML config by template name -// if query has input param - select another tempalte by this name +// if query has input param - select another template by this name // if there is no another template - use input param as template +// After input param processed - remove it to allow a correct parseArgs Codec selection func inputTemplate(name, s string, query url.Values) string { var template string if input := query.Get("input"); input != "" { @@ -114,6 +116,7 @@ func inputTemplate(name, s string, query url.Values) string { } else { template = defaults[name] } + query.Del("input") return strings.Replace(template, "{input}", s, 1) } @@ -188,7 +191,7 @@ func parseArgs(s string) *ffmpeg.Args { // 3. `video` params (support multiple) // 4. `audio` params (support multiple) // 5. `hardware` param - if query != nil { + if len(query) != 0 { // 1. Process raw params for FFmpeg for _, raw := range query["raw"] { args.AddCodec(raw) From f94cd16cb7e15497cdefedb96b0779bc74367ef9 Mon Sep 17 00:00:00 2001 From: "Galindo, Alex" Date: Thu, 6 Jul 2023 12:08:49 +0200 Subject: [PATCH 2/5] Add framerate parameter option to HTTPs Some HTTP (a.g. JPEG or MJPEG) needs set the input framerate explicitly. --- internal/ffmpeg/ffmpeg.go | 5 +++++ internal/ffmpeg/ffmpeg_test.go | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/internal/ffmpeg/ffmpeg.go b/internal/ffmpeg/ffmpeg.go index bb4886ab..be7e4c26 100644 --- a/internal/ffmpeg/ffmpeg.go +++ b/internal/ffmpeg/ffmpeg.go @@ -144,6 +144,11 @@ func parseArgs(s string) *ffmpeg.Args { switch s[:i] { case "http", "https", "rtmp": args.Input = inputTemplate("http", s, query) + // Some HTTP-JPEG, HTTP-MJPEG needs the input framerate explicitly + if query["framerate"] != nil { + args.Input = "-framerate " + query["framerate"][0] + " " + args.Input + query.Del("framerate") + } case "rtsp", "rtsps": // https://ffmpeg.org/ffmpeg-protocols.html#rtsp // skip unnecessary input tracks diff --git a/internal/ffmpeg/ffmpeg_test.go b/internal/ffmpeg/ffmpeg_test.go index 929d1ae8..f7380927 100644 --- a/internal/ffmpeg/ffmpeg_test.go +++ b/internal/ffmpeg/ffmpeg_test.go @@ -1,8 +1,9 @@ package ffmpeg import ( - "github.com/stretchr/testify/require" "testing" + + "github.com/stretchr/testify/require" ) func TestParseArgs(t *testing.T) { @@ -20,4 +21,16 @@ func TestParseArgs(t *testing.T) { args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080") require.Equal(t, `ffmpeg -hide_banner -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c copy -f mjpeg -`, args.String()) + + args = parseArgs("http://example.com") + require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + args = parseArgs("http://example.com#video=h264") + require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://example.com -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + args = parseArgs("http://example.com#framerate=20") + require.Equal(t, "ffmpeg -hide_banner -framerate 20 -fflags nobuffer -flags low_delay -i http://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + args = parseArgs("http://example.com#framerate=20#video=h264") + require.Equal(t, "ffmpeg -hide_banner -framerate 20 -fflags nobuffer -flags low_delay -i http://example.com -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) } From 2ce72dbcca34011fab18f64c348e742669187dc3 Mon Sep 17 00:00:00 2001 From: "Galindo, Alex" Date: Thu, 6 Jul 2023 16:27:23 +0200 Subject: [PATCH 3/5] Add more ffmpeg Test --- internal/ffmpeg/ffmpeg_test.go | 221 +++++++++++++++++++++++++++++++-- 1 file changed, 211 insertions(+), 10 deletions(-) diff --git a/internal/ffmpeg/ffmpeg_test.go b/internal/ffmpeg/ffmpeg_test.go index f7380927..7b7b43e2 100644 --- a/internal/ffmpeg/ffmpeg_test.go +++ b/internal/ffmpeg/ffmpeg_test.go @@ -6,31 +6,232 @@ import ( "github.com/stretchr/testify/require" ) -func TestParseArgs(t *testing.T) { - args := parseArgs("rtsp://example.com#video=h264#rotate=180") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -vf transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) +func TestParseArgsFile(t *testing.T) { + // [FILE] all tracks will be copied without transcoding codecs + args := parseArgs("/media/bbb.mp4") + require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) - args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=vaapi") - require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload,transpose_vaapi=4 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + // [FILE] video will be transcoded to H264, audio will be skipped + args = parseArgs("/media/bbb.mp4#video=h264") + require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + // [FILE] video will be copied, audio will be transcoded to pcmu + args = parseArgs("/media/bbb.mp4#video=copy#audio=pcmu") + require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v copy -c:a pcm_mulaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [FILE] video will be transcoded to H265 and rotate 270º, audio will be skipped + args = parseArgs("/media/bbb.mp4#video=h265#rotate=-90") + require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -an -vf transpose=2 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [FILE] video will be output for MJPEG to pipe, audio will be skipped args = parseArgs("/media/bbb.mp4#video=mjpeg") require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v mjpeg -an -f mjpeg -", args.String()) +} - args = parseArgs("/media/bbb.mp4#video=mjpeg#hardware=vaapi") - require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -re -i /media/bbb.mp4 -c:v mjpeg_vaapi -an -vf format=vaapi|nv12,hwupload -f mjpeg -", args.String()) - - args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080") +func TestParseArgsDevice(t *testing.T) { + // [DEVICE] video will be output for MJPEG to pipe, with size 1920x1080 + args := parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080") require.Equal(t, `ffmpeg -hide_banner -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c copy -f mjpeg -`, args.String()) - args = parseArgs("http://example.com") + // [DEVICE] video will be transcoded to H264 with framerate 20, audio will be skipped + args = parseArgs("device?video=0&framerate=20#video=h264") + require.Equal(t, `ffmpeg -hide_banner -f dshow -framerate 20 -i video="0" -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) + + // [DEVICE] video will be transcoded to H265 with framerate 20, audio will be skipped + args = parseArgs("device?video=0&input_format=mjpeg&video_size=1280x720&framerate=20#video=h265#audio=pcma") + require.Equal(t, `ffmpeg -hide_banner -f dshow -input_format mjpeg -video_size 1280x720 -framerate 20 -i video="0" -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -c:a pcm_alaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) +} + +func TestParseArgsIpCam(t *testing.T) { + // [HTTP] video will be copied + args := parseArgs("http://example.com") require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + // [HTTP-MJPEG] video will be transcoded to H264 args = parseArgs("http://example.com#video=h264") require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://example.com -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + // [HTTP-MJPEG] video will copy, need of set frame rate explicitly args = parseArgs("http://example.com#framerate=20") require.Equal(t, "ffmpeg -hide_banner -framerate 20 -fflags nobuffer -flags low_delay -i http://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly args = parseArgs("http://example.com#framerate=20#video=h264") require.Equal(t, "ffmpeg -hide_banner -framerate 20 -fflags nobuffer -flags low_delay -i http://example.com -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [HLS] video will be copied, audio will be skipped + args = parseArgs("https://example.com#video=copy") + require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i https://example.com -c:v copy -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video will be copied without transcoding codecs + args = parseArgs("rtsp://example.com") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video+audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 + args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -an -vf scale=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video will be copied, changing RTSP transport from TCP to UDP+TCP + args = parseArgs("rtsp://example.com#input=rtsp/udp") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video+audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -i rtsp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTMP] video will be copied, changing RTSP transport from TCP to UDP+TCP + args = parseArgs("rtmp://example.com#input=rtsp/udp") + require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -i rtmp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) +} + +func TestParseArgsAudio(t *testing.T) { + // [AUDIO] audio will be transcoded to AAC, video will be skipped + args := parseArgs("rtsp:///example.com#audio=aac") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a aac -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [AUDIO] audio will be transcoded to AAC/16000, video will be skipped + args = parseArgs("rtsp:///example.com#audio=aac/16000") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a aac -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [AUDIO] audio will be transcoded to OPUS, video will be skipped + args = parseArgs("rtsp:///example.com#audio=opus") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a libopus -ar:a 48000 -ac:a 2 -application:a voip -compression_level:a 0 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [AUDIO] audio will be transcoded to PCMU, video will be skipped + args = parseArgs("rtsp:///example.com#audio=pcmu") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [AUDIO] audio will be transcoded to PCMU/16000, video will be skipped + args = parseArgs("rtsp:///example.com#audio=pcmu/16000") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [AUDIO] audio will be transcoded to PCMU/48000, video will be skipped + args = parseArgs("rtsp:///example.com#audio=pcmu/48000") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 48000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [AUDIO] audio will be transcoded to PCMA, video will be skipped + args = parseArgs("rtsp:///example.com#audio=pcma") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [AUDIO] audio will be transcoded to PCMA/16000, video will be skipped + args = parseArgs("rtsp:///example.com#audio=pcma/16000") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [AUDIO] audio will be transcoded to PCMA/48000, video will be skipped + args = parseArgs("rtsp:///example.com#audio=pcma/48000") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 48000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) +} + +func TestParseArgsHwVaapi(t *testing.T) { + // [HTTP-MJPEG] video will be transcoded to H264 + args := parseArgs("http:///example.com#video=h264#hardware=vaapi") + require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly + args = parseArgs("http://example.com#video=h264#framerate=10#hardware=vaapi") + require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with rotation, should be transcoded, so select H264 + args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=vaapi") + require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload,transpose_vaapi=4 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 + args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=vaapi") + require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_vaapi -g 50 -bf 0 -profile:v high -level:v 5.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload,scale_vaapi=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [FILE] video will be output for MJPEG to pipe, audio will be skipped + args = parseArgs("/media/bbb.mp4#video=mjpeg#hardware=vaapi") + require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -re -i /media/bbb.mp4 -c:v mjpeg_vaapi -an -vf format=vaapi|nv12,hwupload -f mjpeg -", args.String()) + + // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 + args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=vaapi") + require.Equal(t, `ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_vaapi -g 50 -bf 0 -profile:v high -level:v 5.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) +} + +func TestParseArgsHwV4l2m2m(t *testing.T) { + // [HTTP-MJPEG] video will be transcoded to H264 + args := parseArgs("http:///example.com#video=h264#hardware=v4l2m2m") + require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_v4l2m2m -g 50 -bf 0 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly + args = parseArgs("http://example.com#video=h264#framerate=10#hardware=v4l2m2m") + require.Equal(t, "ffmpeg -hide_banner -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_v4l2m2m -g 50 -bf 0 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with rotation, should be transcoded, so select H264 + args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=v4l2m2m") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_v4l2m2m -g 50 -bf 0 -an -vf transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 + args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=v4l2m2m") + require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_v4l2m2m -g 50 -bf 0 -an -vf scale=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 + args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=v4l2m2m") + require.Equal(t, `ffmpeg -hide_banner -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_v4l2m2m -g 50 -bf 0 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) +} + +func TestParseArgsHwCuda(t *testing.T) { + // [HTTP-MJPEG] video will be transcoded to H264 + args := parseArgs("http:///example.com#video=h264#hardware=cuda") + require.Equal(t, "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly + args = parseArgs("http://example.com#video=h264#framerate=10#hardware=cuda") + require.Equal(t, "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with rotation, should be transcoded, so select H264 + args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=cuda") + require.Equal(t, "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll -an -vf transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 + args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=cuda") + require.Equal(t, "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_nvenc -g 50 -profile:v high -level:v auto -an -vf scale_cuda=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 + args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=cuda") + require.Equal(t, `ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_nvenc -g 50 -profile:v high -level:v auto -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) +} + +func TestParseArgsHwDxva2(t *testing.T) { + // [HTTP-MJPEG] video will be transcoded to H264 + args := parseArgs("http:///example.com#video=h264#hardware=dxva2") + require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly + args = parseArgs("http://example.com#video=h264#framerate=10#hardware=dxva2") + require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with rotation, should be transcoded, so select H264 + args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=dxva2") + require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv,transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 + args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=dxva2") + require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_qsv -g 50 -bf 0 -profile:v high -level:v 5.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv,scale_qsv=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [FILE] video will be output for MJPEG to pipe, audio will be skipped + args = parseArgs("/media/bbb.mp4#video=mjpeg#hardware=dxva2") + require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -re -i /media/bbb.mp4 -c:v mjpeg_qsv -profile:v high -level:v 5.1 -an -vf hwmap=derive_device=qsv,format=qsv -f mjpeg -", args.String()) + + // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 + args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=dxva2") + require.Equal(t, `ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_qsv -g 50 -bf 0 -profile:v high -level:v 5.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) +} + +func TestParseArgsHwVideotoolbox(t *testing.T) { + // [HTTP-MJPEG] video will be transcoded to H264 + args := parseArgs("http:///example.com#video=h264#hardware=videotoolbox") + require.Equal(t, "ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_videotoolbox -g 50 -bf 0 -profile:v high -level:v 4.1 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly + args = parseArgs("http://example.com#video=h264#framerate=10#hardware=videotoolbox") + require.Equal(t, "ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_videotoolbox -g 50 -bf 0 -profile:v high -level:v 4.1 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with rotation, should be transcoded, so select H264 + args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=videotoolbox") + require.Equal(t, "ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_videotoolbox -g 50 -bf 0 -profile:v high -level:v 4.1 -an -vf transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 + args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=videotoolbox") + require.Equal(t, "ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_videotoolbox -g 50 -bf 0 -profile:v high -level:v 5.1 -an -vf scale=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + + // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 + args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=videotoolbox") + require.Equal(t, `ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_videotoolbox -g 50 -bf 0 -profile:v high -level:v 5.1 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) } From f0d627fa5587f39a3e9571edd1ae57edfa477e97 Mon Sep 17 00:00:00 2001 From: "Galindo, Alex" Date: Fri, 7 Jul 2023 14:03:53 +0200 Subject: [PATCH 4/5] Revert "Add framerate parameter option to HTTPs" This reverts commit f94cd16cb7e15497cdefedb96b0779bc74367ef9. --- internal/ffmpeg/ffmpeg.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/internal/ffmpeg/ffmpeg.go b/internal/ffmpeg/ffmpeg.go index 0d8e0ab4..287206d2 100644 --- a/internal/ffmpeg/ffmpeg.go +++ b/internal/ffmpeg/ffmpeg.go @@ -152,11 +152,6 @@ func parseArgs(s string) *ffmpeg.Args { switch s[:i] { case "http", "https", "rtmp": args.Input = inputTemplate("http", s, query) - // Some HTTP-JPEG, HTTP-MJPEG needs the input framerate explicitly - if query["framerate"] != nil { - args.Input = "-framerate " + query["framerate"][0] + " " + args.Input - query.Del("framerate") - } case "rtsp", "rtsps": // https://ffmpeg.org/ffmpeg-protocols.html#rtsp // skip unnecessary input tracks From 67b25015df9fb4e414e11d098c7b11ec7c3da2dc Mon Sep 17 00:00:00 2001 From: agalindo Date: Fri, 7 Jul 2023 17:18:01 +0200 Subject: [PATCH 5/5] Update de ffmpeg test after sync --- internal/ffmpeg/ffmpeg_test.go | 136 +++++++++++++-------------------- 1 file changed, 52 insertions(+), 84 deletions(-) diff --git a/internal/ffmpeg/ffmpeg_test.go b/internal/ffmpeg/ffmpeg_test.go index 7b7b43e2..fe78c7c9 100644 --- a/internal/ffmpeg/ffmpeg_test.go +++ b/internal/ffmpeg/ffmpeg_test.go @@ -9,229 +9,197 @@ import ( func TestParseArgsFile(t *testing.T) { // [FILE] all tracks will be copied without transcoding codecs args := parseArgs("/media/bbb.mp4") - require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -re -i /media/bbb.mp4 -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [FILE] video will be transcoded to H264, audio will be skipped args = parseArgs("/media/bbb.mp4#video=h264") - require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [FILE] video will be copied, audio will be transcoded to pcmu args = parseArgs("/media/bbb.mp4#video=copy#audio=pcmu") - require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v copy -c:a pcm_mulaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v copy -c:a pcm_mulaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [FILE] video will be transcoded to H265 and rotate 270º, audio will be skipped args = parseArgs("/media/bbb.mp4#video=h265#rotate=-90") - require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -an -vf transpose=2 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -an -vf "transpose=2" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [FILE] video will be output for MJPEG to pipe, audio will be skipped args = parseArgs("/media/bbb.mp4#video=mjpeg") - require.Equal(t, "ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v mjpeg -an -f mjpeg -", args.String()) + require.Equal(t, `ffmpeg -hide_banner -re -i /media/bbb.mp4 -c:v mjpeg -an -f mjpeg -`, args.String()) } func TestParseArgsDevice(t *testing.T) { // [DEVICE] video will be output for MJPEG to pipe, with size 1920x1080 - args := parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080") - require.Equal(t, `ffmpeg -hide_banner -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c copy -f mjpeg -`, args.String()) - - // [DEVICE] video will be transcoded to H264 with framerate 20, audio will be skipped - args = parseArgs("device?video=0&framerate=20#video=h264") - require.Equal(t, `ffmpeg -hide_banner -f dshow -framerate 20 -i video="0" -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) + args := parseArgs("device?video=0&video_size=1920x1080") + require.Equal(t, `ffmpeg -hide_banner -f dshow -video_size 1920x1080 -i video="0" -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [DEVICE] video will be transcoded to H265 with framerate 20, audio will be skipped - args = parseArgs("device?video=0&input_format=mjpeg&video_size=1280x720&framerate=20#video=h265#audio=pcma") - require.Equal(t, `ffmpeg -hide_banner -f dshow -input_format mjpeg -video_size 1280x720 -framerate 20 -i video="0" -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -c:a pcm_alaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) + args = parseArgs("device?video=0&video_size=1280x720&framerate=20#video=h265#audio=pcma") + require.Equal(t, `ffmpeg -hide_banner -f dshow -video_size 1280x720 -framerate 20 -i video="0" -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -c:a pcm_alaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) } func TestParseArgsIpCam(t *testing.T) { // [HTTP] video will be copied args := parseArgs("http://example.com") - require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [HTTP-MJPEG] video will be transcoded to H264 args = parseArgs("http://example.com#video=h264") - require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://example.com -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) - - // [HTTP-MJPEG] video will copy, need of set frame rate explicitly - args = parseArgs("http://example.com#framerate=20") - require.Equal(t, "ffmpeg -hide_banner -framerate 20 -fflags nobuffer -flags low_delay -i http://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) - - // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly - args = parseArgs("http://example.com#framerate=20#video=h264") - require.Equal(t, "ffmpeg -hide_banner -framerate 20 -fflags nobuffer -flags low_delay -i http://example.com -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http://example.com -c:v libx264 -g 50 -profile:v high -level:v 4.1 -preset:v superfast -tune:v zerolatency -pix_fmt:v yuvj420p -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [HLS] video will be copied, audio will be skipped args = parseArgs("https://example.com#video=copy") - require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i https://example.com -c:v copy -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i https://example.com -c:v copy -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video will be copied without transcoding codecs args = parseArgs("rtsp://example.com") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video+audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types video+audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -an -vf scale=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v libx265 -g 50 -profile:v main -level:v 5.1 -preset:v superfast -tune:v zerolatency -an -vf "scale=1280:720" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video will be copied, changing RTSP transport from TCP to UDP+TCP args = parseArgs("rtsp://example.com#input=rtsp/udp") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video+audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -i rtsp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types video+audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -i rtsp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTMP] video will be copied, changing RTSP transport from TCP to UDP+TCP args = parseArgs("rtmp://example.com#input=rtsp/udp") - require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -i rtmp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -i rtmp://example.com -c copy -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) } func TestParseArgsAudio(t *testing.T) { // [AUDIO] audio will be transcoded to AAC, video will be skipped args := parseArgs("rtsp:///example.com#audio=aac") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a aac -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a aac -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [AUDIO] audio will be transcoded to AAC/16000, video will be skipped args = parseArgs("rtsp:///example.com#audio=aac/16000") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a aac -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a aac -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [AUDIO] audio will be transcoded to OPUS, video will be skipped args = parseArgs("rtsp:///example.com#audio=opus") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a libopus -ar:a 48000 -ac:a 2 -application:a voip -compression_level:a 0 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a libopus -ar:a 48000 -ac:a 2 -application:a voip -af adelay=0|0 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [AUDIO] audio will be transcoded to PCMU, video will be skipped args = parseArgs("rtsp:///example.com#audio=pcmu") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [AUDIO] audio will be transcoded to PCMU/16000, video will be skipped args = parseArgs("rtsp:///example.com#audio=pcmu/16000") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [AUDIO] audio will be transcoded to PCMU/48000, video will be skipped args = parseArgs("rtsp:///example.com#audio=pcmu/48000") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 48000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_mulaw -ar:a 48000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [AUDIO] audio will be transcoded to PCMA, video will be skipped args = parseArgs("rtsp:///example.com#audio=pcma") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 8000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [AUDIO] audio will be transcoded to PCMA/16000, video will be skipped args = parseArgs("rtsp:///example.com#audio=pcma/16000") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 16000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [AUDIO] audio will be transcoded to PCMA/48000, video will be skipped args = parseArgs("rtsp:///example.com#audio=pcma/48000") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 48000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types audio -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp:///example.com -vn -c:a pcm_alaw -ar:a 48000 -ac:a 1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) } func TestParseArgsHwVaapi(t *testing.T) { // [HTTP-MJPEG] video will be transcoded to H264 args := parseArgs("http:///example.com#video=h264#hardware=vaapi") - require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) - - // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly - args = parseArgs("http://example.com#video=h264#framerate=10#hardware=vaapi") - require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf "format=vaapi|nv12,hwupload" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with rotation, should be transcoded, so select H264 args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=vaapi") - require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload,transpose_vaapi=4 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_vaapi -g 50 -bf 0 -profile:v high -level:v 4.1 -sei:v 0 -an -vf "format=vaapi|nv12,hwupload,transpose_vaapi=4" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=vaapi") - require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_vaapi -g 50 -bf 0 -profile:v high -level:v 5.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload,scale_vaapi=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_vaapi -g 50 -bf 0 -profile:v high -level:v 5.1 -sei:v 0 -an -vf "format=vaapi|nv12,hwupload,scale_vaapi=1280:720" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [FILE] video will be output for MJPEG to pipe, audio will be skipped args = parseArgs("/media/bbb.mp4#video=mjpeg#hardware=vaapi") - require.Equal(t, "ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -re -i /media/bbb.mp4 -c:v mjpeg_vaapi -an -vf format=vaapi|nv12,hwupload -f mjpeg -", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -re -i /media/bbb.mp4 -c:v mjpeg_vaapi -an -vf "format=vaapi|nv12,hwupload" -f mjpeg -`, args.String()) // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 - args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=vaapi") - require.Equal(t, `ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_vaapi -g 50 -bf 0 -profile:v high -level:v 5.1 -sei:v 0 -an -vf format=vaapi|nv12,hwupload -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) + args = parseArgs("device?video=0&video_size=1920x1080#video=h265#hardware=vaapi") + require.Equal(t, `ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -f dshow -video_size 1920x1080 -i video="0" -c:v hevc_vaapi -g 50 -bf 0 -profile:v high -level:v 5.1 -sei:v 0 -an -vf "format=vaapi|nv12,hwupload" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) } func TestParseArgsHwV4l2m2m(t *testing.T) { // [HTTP-MJPEG] video will be transcoded to H264 args := parseArgs("http:///example.com#video=h264#hardware=v4l2m2m") - require.Equal(t, "ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_v4l2m2m -g 50 -bf 0 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) - - // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly - args = parseArgs("http://example.com#video=h264#framerate=10#hardware=v4l2m2m") - require.Equal(t, "ffmpeg -hide_banner -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_v4l2m2m -g 50 -bf 0 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_v4l2m2m -g 50 -bf 0 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with rotation, should be transcoded, so select H264 args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=v4l2m2m") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_v4l2m2m -g 50 -bf 0 -an -vf transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_v4l2m2m -g 50 -bf 0 -an -vf "transpose=1,transpose=1" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=v4l2m2m") - require.Equal(t, "ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_v4l2m2m -g 50 -bf 0 -an -vf scale=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_v4l2m2m -g 50 -bf 0 -an -vf "scale=1280:720" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 - args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=v4l2m2m") - require.Equal(t, `ffmpeg -hide_banner -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_v4l2m2m -g 50 -bf 0 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) + args = parseArgs("device?video=0&video_size=1920x1080#video=h265#hardware=v4l2m2m") + require.Equal(t, `ffmpeg -hide_banner -f dshow -video_size 1920x1080 -i video="0" -c:v hevc_v4l2m2m -g 50 -bf 0 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) } func TestParseArgsHwCuda(t *testing.T) { // [HTTP-MJPEG] video will be transcoded to H264 args := parseArgs("http:///example.com#video=h264#hardware=cuda") - require.Equal(t, "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) - - // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly - args = parseArgs("http://example.com#video=h264#framerate=10#hardware=cuda") - require.Equal(t, "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_nvenc -g 50 -bf 0 -profile:v high -level:v auto -preset:v p2 -tune:v ll -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with rotation, should be transcoded, so select H264 args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=cuda") - require.Equal(t, "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll -an -vf transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format nv12 -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_nvenc -g 50 -bf 0 -profile:v high -level:v auto -preset:v p2 -tune:v ll -an -vf "transpose=1,transpose=1,hwupload" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=cuda") - require.Equal(t, "ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_nvenc -g 50 -profile:v high -level:v auto -an -vf scale_cuda=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_nvenc -g 50 -bf 0 -profile:v high -level:v auto -an -vf "scale_cuda=1280:720" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 - args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=cuda") - require.Equal(t, `ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_nvenc -g 50 -profile:v high -level:v auto -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) + args = parseArgs("device?video=0&video_size=1920x1080#video=h265#hardware=cuda") + require.Equal(t, `ffmpeg -hide_banner -hwaccel cuda -hwaccel_output_format cuda -f dshow -video_size 1920x1080 -i video="0" -c:v hevc_nvenc -g 50 -bf 0 -profile:v high -level:v auto -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) } func TestParseArgsHwDxva2(t *testing.T) { // [HTTP-MJPEG] video will be transcoded to H264 args := parseArgs("http:///example.com#video=h264#hardware=dxva2") - require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) - - // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly - args = parseArgs("http://example.com#video=h264#framerate=10#hardware=dxva2") - require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 -an -vf "hwmap=derive_device=qsv,format=qsv" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with rotation, should be transcoded, so select H264 args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=dxva2") - require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv,transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1 -an -vf "hwmap=derive_device=qsv,format=qsv,transpose=1,transpose=1" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=dxva2") - require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_qsv -g 50 -bf 0 -profile:v high -level:v 5.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv,scale_qsv=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_qsv -g 50 -bf 0 -profile:v high -level:v 5.1 -async_depth:v 1 -an -vf "hwmap=derive_device=qsv,format=qsv,scale_qsv=1280:720" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [FILE] video will be output for MJPEG to pipe, audio will be skipped args = parseArgs("/media/bbb.mp4#video=mjpeg#hardware=dxva2") - require.Equal(t, "ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -re -i /media/bbb.mp4 -c:v mjpeg_qsv -profile:v high -level:v 5.1 -an -vf hwmap=derive_device=qsv,format=qsv -f mjpeg -", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -re -i /media/bbb.mp4 -c:v mjpeg_qsv -profile:v high -level:v 5.1 -an -vf "hwmap=derive_device=qsv,format=qsv" -f mjpeg -`, args.String()) // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 - args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=dxva2") - require.Equal(t, `ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_qsv -g 50 -bf 0 -profile:v high -level:v 5.1 -async_depth:v 1 -an -vf hwmap=derive_device=qsv,format=qsv -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) + args = parseArgs("device?video=0&video_size=1920x1080#video=h265#hardware=dxva2") + require.Equal(t, `ffmpeg -hide_banner -hwaccel dxva2 -hwaccel_output_format dxva2_vld -f dshow -video_size 1920x1080 -i video="0" -c:v hevc_qsv -g 50 -bf 0 -profile:v high -level:v 5.1 -async_depth:v 1 -an -vf "hwmap=derive_device=qsv,format=qsv" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) } func TestParseArgsHwVideotoolbox(t *testing.T) { // [HTTP-MJPEG] video will be transcoded to H264 args := parseArgs("http:///example.com#video=h264#hardware=videotoolbox") - require.Equal(t, "ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_videotoolbox -g 50 -bf 0 -profile:v high -level:v 4.1 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) - - // [HTTP-MJPEG] video will be transcoded to H264, need of set frame rate explicitly - args = parseArgs("http://example.com#video=h264#framerate=10#hardware=videotoolbox") - require.Equal(t, "ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -framerate 10 -fflags nobuffer -flags low_delay -i http://example.com -c:v h264_videotoolbox -g 50 -bf 0 -profile:v high -level:v 4.1 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -fflags nobuffer -flags low_delay -i http:///example.com -c:v h264_videotoolbox -g 50 -bf 0 -profile:v high -level:v 4.1 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with rotation, should be transcoded, so select H264 args = parseArgs("rtsp://example.com#video=h264#rotate=180#hardware=videotoolbox") - require.Equal(t, "ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_videotoolbox -g 50 -bf 0 -profile:v high -level:v 4.1 -an -vf transpose=1,transpose=1 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v h264_videotoolbox -g 50 -bf 0 -profile:v high -level:v 4.1 -an -vf "transpose=1,transpose=1" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [RTSP] video with resize to 1280x720, should be transcoded, so select H265 args = parseArgs("rtsp://example.com#video=h265#width=1280#height=720#hardware=videotoolbox") - require.Equal(t, "ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_videotoolbox -g 50 -bf 0 -profile:v high -level:v 5.1 -an -vf scale=1280:720 -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}", args.String()) + require.Equal(t, `ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -allowed_media_types video -fflags nobuffer -flags low_delay -timeout 5000000 -user_agent go2rtc/ffmpeg -rtsp_flags prefer_tcp -i rtsp://example.com -c:v hevc_videotoolbox -g 50 -bf 0 -profile:v high -level:v 5.1 -an -vf "scale=1280:720" -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) // [DEVICE] MJPEG video with size 1920x1080 will be transcoded to H265 - args = parseArgs("device?video=0&input_format=mjpeg&video_size=1920x1080#video=h265#hardware=videotoolbox") - require.Equal(t, `ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -f dshow -input_format mjpeg -video_size 1920x1080 -i video="0" -c:v hevc_videotoolbox -g 50 -bf 0 -profile:v high -level:v 5.1 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) + args = parseArgs("device?video=0&video_size=1920x1080#video=h265#hardware=videotoolbox") + require.Equal(t, `ffmpeg -hide_banner -hwaccel videotoolbox -hwaccel_output_format videotoolbox_vld -f dshow -video_size 1920x1080 -i video="0" -c:v hevc_videotoolbox -g 50 -bf 0 -profile:v high -level:v 5.1 -an -user_agent ffmpeg/go2rtc -rtsp_transport tcp -f rtsp {output}`, args.String()) }