diff --git a/transcoder/src/hwaccel.go b/transcoder/src/hwaccel.go new file mode 100644 index 00000000..0405be6d --- /dev/null +++ b/transcoder/src/hwaccel.go @@ -0,0 +1,32 @@ +package src + +func DetectHardwareAccel() HwAccelT { + name := "disabled" + switch name { + case "nvidia": + return HwAccelT{ + Name: "nvidia", + DecodeFlags: []string{ + // TODO: check if this can always be enabled (for example with weird video formats) + "-hwaccel", "cuda", + // this flag prevents data to go from gpu space to cpu space + // it forces the whole dec/enc to be on the gpu. We want that. + "-hwaccel_output_format", "cuda", + }, + EncodeFlags: []string{ + "-c:v", "h264_nvenc", + "-preset", "fast", + }, + } + default: + return HwAccelT{ + Name: "disabled", + DecodeFlags: []string{}, + EncodeFlags: []string{ + "-c:v", "libx264", + // superfast or ultrafast would produce a file extremly big so we prever veryfast or faster. + "-preset", "faster", + }, + } + } +} diff --git a/transcoder/src/settings.go b/transcoder/src/settings.go index 456f982e..c54573e3 100644 --- a/transcoder/src/settings.go +++ b/transcoder/src/settings.go @@ -13,9 +13,17 @@ func GetEnvOr(env string, def string) string { type SettingsT struct { Outpath string Metadata string + HwAccel HwAccelT +} + +type HwAccelT struct { + Name string + DecodeFlags []string + EncodeFlags []string } var Settings = SettingsT{ Outpath: GetEnvOr("GOCODER_CACHE_ROOT", "/cache"), Metadata: GetEnvOr("GOCODER_METADATA_ROOT", "/metadata"), + HwAccel: DetectHardwareAccel(), } diff --git a/transcoder/src/stream.go b/transcoder/src/stream.go index df516574..af19ef4f 100644 --- a/transcoder/src/stream.go +++ b/transcoder/src/stream.go @@ -18,8 +18,9 @@ import ( type Flags int32 const ( - AudioF Flags = 1 << 0 - VideoF Flags = 1 << 1 + AudioF Flags = 1 << 0 + VideoF Flags = 1 << 1 + Transmux Flags = 1 << 3 ) type StreamHandle interface { @@ -166,6 +167,12 @@ func (ts *Stream) run(start int32) error { "-nostats", "-hide_banner", "-loglevel", "warning", } + // do not enabled hardware accelaration when transmuxing + // this can either be slower or fail depending on hardware + if ts.handle.getFlags()&Transmux == 0 { + args = append(args, Settings.HwAccel.DecodeFlags...) + } + if start_ref != 0 { if ts.handle.getFlags()&VideoF != 0 { // This is the default behavior in transmux mode and needed to force pre/post segment to work diff --git a/transcoder/src/videostream.go b/transcoder/src/videostream.go index 793c4900..af476f22 100644 --- a/transcoder/src/videostream.go +++ b/transcoder/src/videostream.go @@ -19,6 +19,9 @@ func NewVideoStream(file *FileStream, quality Quality) *VideoStream { } func (vs *VideoStream) getFlags() Flags { + if vs.quality == Original { + return VideoF & Transmux + } return VideoF } @@ -27,18 +30,24 @@ func (vs *VideoStream) getOutPath(encoder_id int) string { } func (vs *VideoStream) getTranscodeArgs(segments string) []string { - if vs.quality == Original { - return []string{"-map", "0:V:0", "-c:v", "copy"} + args := []string{ + "-map", "0:V:0", } - return []string{ - // superfast or ultrafast would produce a file extremly big so we prever veryfast or faster. - "-map", "0:V:0", "-c:v", "libx264", "-crf", "21", "-preset", "faster", + if vs.quality == Original { + args = append(args, + "-c:v", "copy", + ) + return args + } + + args = append(args, Settings.HwAccel.EncodeFlags...) + args = append(args, // resize but keep aspect ratio (also force a width that is a multiple of two else some apps behave badly. "-vf", fmt.Sprintf("scale=-2:'min(%d,ih)'", vs.quality.Height()), // Even less sure but bufsize are 5x the avergae bitrate since the average bitrate is only // useful for hls segments. - "-bufsize", fmt.Sprint(vs.quality.MaxBitrate() * 5), + "-bufsize", fmt.Sprint(vs.quality.MaxBitrate()*5), "-b:v", fmt.Sprint(vs.quality.AverageBitrate()), "-maxrate", fmt.Sprint(vs.quality.MaxBitrate()), // Force segments to be split exactly on keyframes (only works when transcoding) @@ -48,5 +57,6 @@ func (vs *VideoStream) getTranscodeArgs(segments string) []string { // we disable it to prevents whole scenes from behing removed due to the -f segment failing to find the corresonding keyframe "-sc_threshold", "0", "-strict", "-2", - } + ) + return args }