diff --git a/pkg/config/config.yaml b/pkg/config/config.yaml index d1402f3c9..460ca86f1 100644 --- a/pkg/config/config.yaml +++ b/pkg/config/config.yaml @@ -300,8 +300,15 @@ encoder: threads: 0 # see: https://trac.ffmpeg.org/wiki/Encode/H.264 h264: + # crf, cbr + mode: crf # Constant Rate Factor (CRF) 0-51 (default: 23) crf: 23 + # Rate control options + # set the maximum bitrate + maxRate: 0 + # set the expected client buffer size + bufSize: 0 # ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo preset: superfast # baseline, main, high, high10, high422, high444 diff --git a/pkg/config/worker.go b/pkg/config/worker.go index 5fd4ef23a..21da91e64 100644 --- a/pkg/config/worker.go +++ b/pkg/config/worker.go @@ -58,7 +58,10 @@ type Video struct { Codec string Threads int H264 struct { + Mode string Crf uint8 + MaxRate int + BufSize int LogLevel int32 Preset string Profile string diff --git a/pkg/encoder/h264/x264.go b/pkg/encoder/h264/x264.go index 5b792487c..58259ff46 100644 --- a/pkg/encoder/h264/x264.go +++ b/pkg/encoder/h264/x264.go @@ -69,6 +69,7 @@ import "C" import ( "fmt" + "strings" "unsafe" ) @@ -77,11 +78,16 @@ type H264 struct { } type Options struct { + Mode string // Constant Rate Factor (CRF) // This method allows the encoder to attempt to achieve a certain output quality for the whole file // when output file size is of less importance. // The range of the CRF scale is 0–51, where 0 is lossless, 23 is the default, and 51 is the worst quality possible. - Crf uint8 + Crf uint8 + // vbv-maxrate + MaxRate int + // vbv-bufsize + BufSize int LogLevel int32 // ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo. Preset string @@ -100,6 +106,7 @@ func NewEncoder(w, h int, th int, opts *Options) (encoder *H264, err error) { if opts == nil { opts = &Options{ + Mode: "crf", Crf: 23, Tune: "zerolatency", Preset: "superfast", @@ -144,9 +151,23 @@ func NewEncoder(w, h int, th int, opts *Options) (encoder *H264, err error) { if th != 1 { param.b_sliced_threads = 1 } + param.rc.i_rc_method = C.X264_RC_CRF param.rc.f_rf_constant = C.float(opts.Crf) + if strings.ToLower(opts.Mode) == "cbr" { + param.rc.i_rc_method = C.X264_RC_ABR + param.i_nal_hrd = C.X264_NAL_HRD_CBR + } + + if opts.MaxRate > 0 { + param.rc.i_bitrate = C.int(opts.MaxRate) + param.rc.i_vbv_max_bitrate = C.int(opts.MaxRate) + } + if opts.BufSize > 0 { + param.rc.i_vbv_buffer_size = C.int(opts.BufSize) + } + h264 := C.h264_new(¶m) if h264 == nil { return nil, fmt.Errorf("x264: cannot open the encoder")