Add video codec profiles (#5154)

This commit is contained in:
NodudeWasTaken
2024-08-27 10:03:48 +02:00
committed by GitHub
parent 3089e1ad69
commit ce47efc415
5 changed files with 80 additions and 49 deletions

View File

@@ -1,25 +1,32 @@
package ffmpeg
type VideoCodec string
type VideoCodec struct {
Name string // The full name of the codec including profile/quality
CodeName string // The core codec name without profile/quality suffix
}
func makeVideoCodec(name string, codename string) VideoCodec {
return VideoCodec{name, codename}
}
func (c VideoCodec) Args() []string {
if c == "" {
if c.CodeName == "" {
return nil
}
return []string{"-c:v", string(c)}
return []string{"-c:v", string(c.CodeName)}
}
var (
// Software codec's
VideoCodecLibX264 VideoCodec = "libx264"
VideoCodecLibWebP VideoCodec = "libwebp"
VideoCodecBMP VideoCodec = "bmp"
VideoCodecMJpeg VideoCodec = "mjpeg"
VideoCodecVP9 VideoCodec = "libvpx-vp9"
VideoCodecVPX VideoCodec = "libvpx"
VideoCodecLibX265 VideoCodec = "libx265"
VideoCodecCopy VideoCodec = "copy"
VideoCodecLibX264 = makeVideoCodec("x264", "libx264")
VideoCodecLibWebP = makeVideoCodec("WebP", "libwebp")
VideoCodecBMP = makeVideoCodec("BMP", "bmp")
VideoCodecMJpeg = makeVideoCodec("Jpeg", "mjpeg")
VideoCodecVP9 = makeVideoCodec("VPX-VP9", "libvpx-vp9")
VideoCodecVPX = makeVideoCodec("VPX-VP8", "libvpx")
VideoCodecLibX265 = makeVideoCodec("x265", "libx265")
VideoCodecCopy = makeVideoCodec("Copy", "copy")
)
type AudioCodec string

View File

@@ -15,16 +15,18 @@ import (
var (
// Hardware codec's
VideoCodecN264 VideoCodec = "h264_nvenc"
VideoCodecI264 VideoCodec = "h264_qsv"
VideoCodecA264 VideoCodec = "h264_amf"
VideoCodecM264 VideoCodec = "h264_videotoolbox"
VideoCodecV264 VideoCodec = "h264_vaapi"
VideoCodecR264 VideoCodec = "h264_v4l2m2m"
VideoCodecO264 VideoCodec = "h264_omx"
VideoCodecIVP9 VideoCodec = "vp9_qsv"
VideoCodecVVP9 VideoCodec = "vp9_vaapi"
VideoCodecVVPX VideoCodec = "vp8_vaapi"
VideoCodecN264 = makeVideoCodec("H264 NVENC", "h264_nvenc")
VideoCodecN264H = makeVideoCodec("H264 NVENC HQ profile", "h264_nvenc")
VideoCodecI264 = makeVideoCodec("H264 Intel Quick Sync Video (QSV)", "h264_qsv")
VideoCodecI264C = makeVideoCodec("H264 Intel Quick Sync Video (QSV) Compatibility profile", "h264_qsv")
VideoCodecA264 = makeVideoCodec("H264 Advanced Media Framework (AMF)", "h264_amf")
VideoCodecM264 = makeVideoCodec("H264 VideoToolbox", "h264_videotoolbox")
VideoCodecV264 = makeVideoCodec("H264 VAAPI", "h264_vaapi")
VideoCodecR264 = makeVideoCodec("H264 V4L2M2M", "h264_v4l2m2m")
VideoCodecO264 = makeVideoCodec("H264 OMX", "h264_omx")
VideoCodecIVP9 = makeVideoCodec("VP9 Intel Quick Sync Video (QSV)", "vp9_qsv")
VideoCodecVVP9 = makeVideoCodec("VP9 VAAPI", "vp9_vaapi")
VideoCodecVVPX = makeVideoCodec("VP8 VAAPI", "vp8_vaapi")
)
const minHeight int = 480
@@ -33,9 +35,12 @@ const minHeight int = 480
func (f *FFMpeg) InitHWSupport(ctx context.Context) {
var hwCodecSupport []VideoCodec
// Note that the first compatible codec is returned, so order is important
for _, codec := range []VideoCodec{
VideoCodecN264H,
VideoCodecN264,
VideoCodecI264,
VideoCodecI264C,
VideoCodecV264,
VideoCodecR264,
VideoCodecIVP9,
@@ -79,7 +84,7 @@ func (f *FFMpeg) InitHWSupport(ctx context.Context) {
outstr := fmt.Sprintf("[InitHWSupport] Supported HW codecs [%d]:\n", len(hwCodecSupport))
for _, codec := range hwCodecSupport {
outstr += fmt.Sprintf("\t%s\n", codec)
outstr += fmt.Sprintf("\t%s - %s\n", codec.Name, codec.CodeName)
}
logger.Info(outstr)
@@ -128,7 +133,8 @@ func (f *FFMpeg) hwCanFullHWTranscode(ctx context.Context, codec VideoCodec, vf
// Prepend input for hardware encoding only
func (f *FFMpeg) hwDeviceInit(args Args, toCodec VideoCodec, fullhw bool) Args {
switch toCodec {
case VideoCodecN264:
case VideoCodecN264,
VideoCodecN264H:
args = append(args, "-hwaccel_device")
args = append(args, "0")
if fullhw {
@@ -150,6 +156,7 @@ func (f *FFMpeg) hwDeviceInit(args Args, toCodec VideoCodec, fullhw bool) Args {
args = append(args, "vaapi")
}
case VideoCodecI264,
VideoCodecI264C,
VideoCodecIVP9:
if fullhw {
args = append(args, "-hwaccel")
@@ -187,12 +194,13 @@ func (f *FFMpeg) hwFilterInit(toCodec VideoCodec, fullhw bool) VideoFilter {
videoFilter = videoFilter.Append("format=nv12")
videoFilter = videoFilter.Append("hwupload")
}
case VideoCodecN264:
case VideoCodecN264, VideoCodecN264H:
if !fullhw {
videoFilter = videoFilter.Append("format=yuv420p")
videoFilter = videoFilter.Append("format=nv12")
videoFilter = videoFilter.Append("hwupload_cuda")
}
case VideoCodecI264,
VideoCodecI264C,
VideoCodecIVP9:
if !fullhw {
videoFilter = videoFilter.Append("hwupload=extra_hw_frames=64")
@@ -268,7 +276,7 @@ func (f *FFMpeg) hwCodecFilter(args VideoFilter, codec VideoCodec, vf *models.Vi
// Apply format switching if applicable
func (f *FFMpeg) hwApplyFullHWFilter(args VideoFilter, codec VideoCodec, fullhw bool) VideoFilter {
switch codec {
case VideoCodecN264:
case VideoCodecN264, VideoCodecN264H:
if fullhw && f.version.Gteq(FFMpegVersion{major: 5}) { // Added in FFMpeg 5
args = args.Append("scale_cuda=format=yuv420p")
}
@@ -276,7 +284,7 @@ func (f *FFMpeg) hwApplyFullHWFilter(args VideoFilter, codec VideoCodec, fullhw
if fullhw && f.version.Gteq(FFMpegVersion{major: 3, minor: 1}) { // Added in FFMpeg 3.1
args = args.Append("scale_vaapi=format=nv12")
}
case VideoCodecI264, VideoCodecIVP9:
case VideoCodecI264, VideoCodecI264C, VideoCodecIVP9:
if fullhw && f.version.Gteq(FFMpegVersion{major: 3, minor: 3}) { // Added in FFMpeg 3.3
args = args.Append("scale_qsv=format=nv12")
}
@@ -290,7 +298,7 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in
var template string
switch codec {
case VideoCodecN264:
case VideoCodecN264, VideoCodecN264H:
template = "scale_cuda=$value"
if fullhw && f.version.Gteq(FFMpegVersion{major: 5}) { // Added in FFMpeg 5
template += ":format=yuv420p"
@@ -300,7 +308,7 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in
if fullhw && f.version.Gteq(FFMpegVersion{major: 3, minor: 1}) { // Added in FFMpeg 3.1
template += ":format=nv12"
}
case VideoCodecI264, VideoCodecIVP9:
case VideoCodecI264, VideoCodecI264C, VideoCodecIVP9:
template = "scale_qsv=$value"
if fullhw && f.version.Gteq(FFMpegVersion{major: 3, minor: 3}) { // Added in FFMpeg 3.3
template += ":format=nv12"
@@ -312,7 +320,7 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in
}
// BUG: [scale_qsv]: Size values less than -1 are not acceptable.
isIntel := codec == VideoCodecI264 || codec == VideoCodecIVP9
isIntel := codec == VideoCodecI264 || codec == VideoCodecI264C || codec == VideoCodecIVP9
// BUG: scale_vt doesn't call ff_scale_adjust_dimensions, thus cant accept negative size values
isApple := codec == VideoCodecM264
return VideoFilter(templateReplaceScale(sargs, template, match, vf, isIntel || isApple))
@@ -322,7 +330,9 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in
func (f *FFMpeg) hwCodecMaxRes(codec VideoCodec) (int, int) {
switch codec {
case VideoCodecN264,
VideoCodecI264:
VideoCodecN264H,
VideoCodecI264,
VideoCodecI264C:
return 4096, 4096
}
@@ -345,7 +355,9 @@ func (f *FFMpeg) hwCodecHLSCompatible() *VideoCodec {
for _, element := range f.hwCodecSupport {
switch element {
case VideoCodecN264,
VideoCodecN264H,
VideoCodecI264,
VideoCodecI264C,
VideoCodecV264,
VideoCodecR264,
VideoCodecM264: // Note that the Apple encoder sucks at startup, thus HLS quality is crap
@@ -360,7 +372,9 @@ func (f *FFMpeg) hwCodecMP4Compatible() *VideoCodec {
for _, element := range f.hwCodecSupport {
switch element {
case VideoCodecN264,
VideoCodecN264H,
VideoCodecI264,
VideoCodecI264C,
VideoCodecM264:
return &element
}

View File

@@ -45,12 +45,31 @@ func CodecInit(codec VideoCodec) (args Args) {
"-rc", "vbr",
"-cq", "15",
)
case VideoCodecI264:
case VideoCodecN264H:
args = append(args,
"-profile", "p7",
"-tune", "hq",
"-profile", "high",
"-rc", "vbr",
"-rc-lookahead", "60",
"-surfaces", "64",
"-spatial-aq", "1",
"-aq-strength", "15",
"-cq", "15",
"-coder", "cabac",
"-b_ref_mode", "middle",
)
case VideoCodecI264, VideoCodecIVP9:
args = append(args,
"-global_quality", "20",
"-preset", "faster",
)
case VideoCodecV264:
case VideoCodecI264C:
args = append(args,
"-q", "20",
"-preset", "faster",
)
case VideoCodecV264, VideoCodecVVP9:
args = append(args,
"-qp", "20",
)
@@ -67,15 +86,6 @@ func CodecInit(codec VideoCodec) (args Args) {
"-preset", "superfast",
"-crf", "25",
)
case VideoCodecIVP9:
args = append(args,
"-global_quality", "20",
"-preset", "faster",
)
case VideoCodecVVP9:
args = append(args,
"-qp", "20",
)
}
return args

View File

@@ -24,13 +24,13 @@ func (o *ScreenshotOptions) setDefaults() {
}
type ScreenshotOutputType struct {
codec ffmpeg.VideoCodec
codec *ffmpeg.VideoCodec
format ffmpeg.Format
}
func (t ScreenshotOutputType) Args() []string {
var ret []string
if t.codec != "" {
if t.codec != nil {
ret = append(ret, t.codec.Args()...)
}
if t.format != "" {
@@ -45,7 +45,7 @@ var (
format: "image2",
}
ScreenshotOutputTypeBMP = ScreenshotOutputType{
codec: ffmpeg.VideoCodecBMP,
codec: &ffmpeg.VideoCodecBMP,
format: "rawvideo",
}
)

View File

@@ -11,7 +11,7 @@ type SpliceOptions struct {
OutputPath string
Format ffmpeg.Format
VideoCodec ffmpeg.VideoCodec
VideoCodec *ffmpeg.VideoCodec
VideoArgs ffmpeg.Args
AudioCodec ffmpeg.AudioCodec
@@ -45,11 +45,11 @@ func Splice(concatFile string, options SpliceOptions) ffmpeg.Args {
args = args.Overwrite()
// if video codec is not provided, then use copy
if options.VideoCodec == "" {
options.VideoCodec = ffmpeg.VideoCodecCopy
if options.VideoCodec == nil {
options.VideoCodec = &ffmpeg.VideoCodecCopy
}
args = args.VideoCodec(options.VideoCodec)
args = args.VideoCodec(*options.VideoCodec)
args = args.AppendArgs(options.VideoArgs)
// if audio codec is not provided, then use copy