From c34f9ae2b7381e37fa3deca13ce3717d2ff727b5 Mon Sep 17 00:00:00 2001 From: Alexey Khit Date: Mon, 3 Jul 2023 00:45:51 +0300 Subject: [PATCH] Support FFmpeg drawtext param #487 --- Dockerfile | 3 +- internal/ffmpeg/ffmpeg.go | 16 +++++++-- internal/ffmpeg/hardware/hardware.go | 52 +++++++++++++++++++--------- pkg/ffmpeg/ffmpeg.go | 15 +++++++- 4 files changed, 65 insertions(+), 21 deletions(-) diff --git a/Dockerfile b/Dockerfile index 09e6adad..10936d45 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,7 +41,8 @@ FROM base # Install ffmpeg, tini (for signal handling), # and other common tools for the echo source. # alsa-plugins-pulse for ALSA support (+0MB) -RUN apk add --no-cache tini ffmpeg bash curl jq alsa-plugins-pulse +# font-droid for FFmpeg drawtext filter (+2MB) +RUN apk add --no-cache tini ffmpeg bash curl jq alsa-plugins-pulse font-droid # Hardware Acceleration for Intel CPU (+50MB) ARG TARGETARCH diff --git a/internal/ffmpeg/ffmpeg.go b/internal/ffmpeg/ffmpeg.go index 8876283d..b46f5212 100644 --- a/internal/ffmpeg/ffmpeg.go +++ b/internal/ffmpeg/ffmpeg.go @@ -89,8 +89,8 @@ var defaults = map[string]string{ // hardware NVidia on Linux and Windows // preset=p2 - faster, tune=ll - low latency - "h264/cuda": "-c:v h264_nvenc -g 50 -profile:v high -level:v auto -preset:v p2 -tune:v ll", - "h265/cuda": "-c:v hevc_nvenc -g 50 -profile:v high -level:v auto", + "h264/cuda": "-c:v h264_nvenc -g 50 -bf 0 -profile:v high -level:v auto -preset:v p2 -tune:v ll", + "h265/cuda": "-c:v hevc_nvenc -g 50 -bf 0 -profile:v high -level:v auto", // hardware Intel on Windows "h264/dxva2": "-c:v h264_qsv -g 50 -bf 0 -profile:v high -level:v 4.1 -async_depth:v 1", @@ -234,6 +234,18 @@ func parseArgs(s string) *ffmpeg.Args { } } + for _, drawtext := range query["drawtext"] { + // support templates https://github.com/AlexxIT/go2rtc/issues/487 + drawtext = configTemplate(drawtext) + + // support default timestamp format + if !strings.Contains(drawtext, "text=") { + drawtext += `:text='%{localtime\:%Y-%m-%d %X}'` + } + + args.AddFilter("drawtext=" + drawtext) + } + // 3. Process video codecs if args.Video > 0 { for _, video := range query["video"] { diff --git a/internal/ffmpeg/hardware/hardware.go b/internal/ffmpeg/hardware/hardware.go index bb8f7174..d4aa917c 100644 --- a/internal/ffmpeg/hardware/hardware.go +++ b/internal/ffmpeg/hardware/hardware.go @@ -55,33 +55,51 @@ func MakeHardware(args *ffmpeg.Args, engine string, defaults map[string]string) switch engine { case EngineVAAPI: - args.Input = "-hwaccel vaapi -hwaccel_output_format vaapi " + args.Input args.Codecs[i] = defaults[name+"/"+engine] - for i, filter := range args.Filters { - if strings.HasPrefix(filter, "scale=") { - args.Filters[i] = "scale_vaapi=" + filter[6:] - } - if strings.HasPrefix(filter, "transpose=") { - if filter == "transpose=1,transpose=1" { // 180 degrees half-turn - args.Filters[i] = "transpose_vaapi=4" // reversal - } else { - args.Filters[i] = "transpose_vaapi=" + filter[10:] + if !args.HasFilters("drawtext=") { + args.Input = "-hwaccel vaapi -hwaccel_output_format vaapi " + args.Input + + for i, filter := range args.Filters { + if strings.HasPrefix(filter, "scale=") { + args.Filters[i] = "scale_vaapi=" + filter[6:] + } + if strings.HasPrefix(filter, "transpose=") { + if filter == "transpose=1,transpose=1" { // 180 degrees half-turn + args.Filters[i] = "transpose_vaapi=4" // reversal + } else { + args.Filters[i] = "transpose_vaapi=" + filter[10:] + } } } + + // fix if input doesn't support hwaccel, do nothing when support + // insert as first filter before hardware scale and transpose + args.InsertFilter("format=vaapi|nv12,hwupload") + } else { + // enable software pixel for drawtext, scale and transpose + args.Input = "-hwaccel vaapi -hwaccel_output_format nv12 " + args.Input + + args.AddFilter("hwupload") } - // fix if input doesn't support hwaccel, do nothing when support - args.InsertFilter("format=vaapi|nv12,hwupload") - case EngineCUDA: - args.Input = "-hwaccel cuda -hwaccel_output_format cuda -extra_hw_frames 2 " + args.Input args.Codecs[i] = defaults[name+"/"+engine] - for i, filter := range args.Filters { - if strings.HasPrefix(filter, "scale=") { - args.Filters[i] = "scale_cuda=" + filter[6:] + // CUDA doesn't support hardware transpose + // https://github.com/AlexxIT/go2rtc/issues/389 + if !args.HasFilters("drawtext=", "transpose=") { + args.Input = "-hwaccel cuda -hwaccel_output_format cuda " + args.Input + + for i, filter := range args.Filters { + if strings.HasPrefix(filter, "scale=") { + args.Filters[i] = "scale_cuda=" + filter[6:] + } } + } else { + args.Input = "-hwaccel cuda -hwaccel_output_format nv12 " + args.Input + + args.AddFilter("hwupload") } case EngineDXVA2: diff --git a/pkg/ffmpeg/ffmpeg.go b/pkg/ffmpeg/ffmpeg.go index 10fb5bed..a24d9201 100644 --- a/pkg/ffmpeg/ffmpeg.go +++ b/pkg/ffmpeg/ffmpeg.go @@ -29,6 +29,18 @@ func (a *Args) InsertFilter(filter string) { a.Filters = append([]string{filter}, a.Filters...) } +func (a *Args) HasFilters(filters ...string) bool { + for _, f1 := range a.Filters { + for _, f2 := range filters { + if strings.HasPrefix(f1, f2) { + return true + } + } + } + + return false +} + func (a *Args) String() string { b := bytes.NewBuffer(make([]byte, 0, 512)) @@ -65,12 +77,13 @@ func (a *Args) String() string { if a.Filters != nil { for i, filter := range a.Filters { if i == 0 { - b.WriteString(" -vf ") + b.WriteString(` -vf "`) } else { b.WriteByte(',') } b.WriteString(filter) } + b.WriteByte('"') } b.WriteByte(' ')