From 9e153914719d9a20ce35169ca2ad80ee68642a82 Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Sun, 16 Jul 2023 13:43:27 +0300 Subject: [PATCH] Code refactoring after #517 --- README.md | 1 - internal/ffmpeg/helpers.go | 18 ---------- internal/ffmpeg/jpeg.go | 69 ++++++++++++++++++++++++++++++++++++ internal/ffmpeg/jpeg_test.go | 23 ++++++++++++ internal/mjpeg/init.go | 19 ++-------- 5 files changed, 95 insertions(+), 35 deletions(-) delete mode 100644 internal/ffmpeg/helpers.go create mode 100644 internal/ffmpeg/jpeg.go create mode 100644 internal/ffmpeg/jpeg_test.go diff --git a/README.md b/README.md index 375a5ab5..0810cb63 100644 --- a/README.md +++ b/README.md @@ -921,7 +921,6 @@ API examples: - MJPEG stream: `http://192.168.1.123:1984/api/stream.mjpeg?src=camera1` - JPEG snapshots: `http://192.168.1.123:1984/api/frame.jpeg?src=camera1` -- JPEG snapshot resized to 100px: `http://192.168.1.123:1984/api/frame.jpeg?src=camera1&h=100` ### Module: Log diff --git a/internal/ffmpeg/helpers.go b/internal/ffmpeg/helpers.go deleted file mode 100644 index f9e64d86..00000000 --- a/internal/ffmpeg/helpers.go +++ /dev/null @@ -1,18 +0,0 @@ -package ffmpeg - -import ( - "bytes" - "fmt" - "os/exec" -) - -func TranscodeToJPEG(b []byte, height ...int) ([]byte, error) { - cmdArgs := []string{defaults["bin"], "-hide_banner", "-i", "-", "-f", "mjpeg"} - if len(height) > 0 { - cmdArgs = append(cmdArgs, "-vf", fmt.Sprintf("scale=-1:%d", height[0])) - } - cmdArgs = append(cmdArgs, "-") - cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) - cmd.Stdin = bytes.NewBuffer(b) - return cmd.Output() -} diff --git a/internal/ffmpeg/jpeg.go b/internal/ffmpeg/jpeg.go new file mode 100644 index 00000000..ce01f3a1 --- /dev/null +++ b/internal/ffmpeg/jpeg.go @@ -0,0 +1,69 @@ +package ffmpeg + +import ( + "bytes" + "fmt" + "net/url" + "os/exec" + + "github.com/AlexxIT/go2rtc/internal/ffmpeg/hardware" + "github.com/AlexxIT/go2rtc/pkg/core" + "github.com/AlexxIT/go2rtc/pkg/ffmpeg" + "github.com/AlexxIT/go2rtc/pkg/shell" +) + +func TranscodeToJPEG(b []byte, query url.Values) ([]byte, error) { + ffmpegArgs := parseQuery(query) + cmdArgs := shell.QuoteSplit(ffmpegArgs.String()) + cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...) + cmd.Stdin = bytes.NewBuffer(b) + return cmd.Output() +} + +func parseQuery(query url.Values) *ffmpeg.Args { + args := &ffmpeg.Args{ + Bin: defaults["bin"], + Global: defaults["global"], + Input: "-i -", + Codecs: []string{defaults["mjpeg"]}, + Output: defaults["output/mjpeg"], + } + + var width = -1 + var height = -1 + var r, hw string + + for k, v := range query { + switch k { + case "width", "w": + width = core.Atoi(v[0]) + case "height", "h": + height = core.Atoi(v[0]) + case "rotate": + r = v[0] + case "hardware", "hw": + hw = v[0] + } + } + + if width > 0 || height > 0 { + args.AddFilter(fmt.Sprintf("scale=%d:%d", width, height)) + } + + if r != "" { + switch r { + case "90": + args.AddFilter("transpose=1") // 90 degrees clockwise + case "180": + args.AddFilter("transpose=1,transpose=1") + case "-90", "270": + args.AddFilter("transpose=2") // 90 degrees counterclockwise + } + } + + if hw != "" { + hardware.MakeHardware(args, hw, defaults) + } + + return args +} diff --git a/internal/ffmpeg/jpeg_test.go b/internal/ffmpeg/jpeg_test.go new file mode 100644 index 00000000..b1d459b3 --- /dev/null +++ b/internal/ffmpeg/jpeg_test.go @@ -0,0 +1,23 @@ +package ffmpeg + +import ( + "net/url" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParseQuery(t *testing.T) { + args := parseQuery(nil) + require.Equal(t, `ffmpeg -hide_banner -i - -c:v mjpeg -f mjpeg -`, args.String()) + + query, err := url.ParseQuery("h=480") + require.Nil(t, err) + args = parseQuery(query) + require.Equal(t, `ffmpeg -hide_banner -i - -c:v mjpeg -vf "scale=-1:480" -f mjpeg -`, args.String()) + + query, err = url.ParseQuery("hw=vaapi") + require.Nil(t, err) + args = parseQuery(query) + require.Equal(t, `ffmpeg -hide_banner -hwaccel vaapi -hwaccel_output_format vaapi -i - -c:v mjpeg_vaapi -vf "format=vaapi|nv12,hwupload" -f mjpeg -`, args.String()) +} diff --git a/internal/mjpeg/init.go b/internal/mjpeg/init.go index bebe8264..f9a6d451 100644 --- a/internal/mjpeg/init.go +++ b/internal/mjpeg/init.go @@ -61,22 +61,9 @@ func handlerKeyframe(w http.ResponseWriter, r *http.Request) { case core.CodecH264, core.CodecH265: ts := time.Now() var err error - // Resize image if "h" parameter exists - if hParam := r.URL.Query().Get("h"); hParam != "" { - h, err := strconv.Atoi(hParam) - if err != nil { - http.Error(w, "Invalid height parameter", http.StatusBadRequest) - return - } - if data, err = ffmpeg.TranscodeToJPEG(data, h); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } else { - if data, err = ffmpeg.TranscodeToJPEG(data); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } + if data, err = ffmpeg.TranscodeToJPEG(data, r.URL.Query()); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return } log.Debug().Msgf("[mjpeg] transcoding time=%s", time.Since(ts)) }