Code refactoring after #517
This commit is contained in:
@@ -921,7 +921,6 @@ API examples:
|
|||||||
|
|
||||||
- MJPEG stream: `http://192.168.1.123:1984/api/stream.mjpeg?src=camera1`
|
- 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 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
|
### Module: Log
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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())
|
||||||
|
}
|
||||||
+3
-16
@@ -61,22 +61,9 @@ func handlerKeyframe(w http.ResponseWriter, r *http.Request) {
|
|||||||
case core.CodecH264, core.CodecH265:
|
case core.CodecH264, core.CodecH265:
|
||||||
ts := time.Now()
|
ts := time.Now()
|
||||||
var err error
|
var err error
|
||||||
// Resize image if "h" parameter exists
|
if data, err = ffmpeg.TranscodeToJPEG(data, r.URL.Query()); err != nil {
|
||||||
if hParam := r.URL.Query().Get("h"); hParam != "" {
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
h, err := strconv.Atoi(hParam)
|
return
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
log.Debug().Msgf("[mjpeg] transcoding time=%s", time.Since(ts))
|
log.Debug().Msgf("[mjpeg] transcoding time=%s", time.Since(ts))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user