Config: Downscale videos based on largest dimension (#3510)

* Adds resolution limit

* Fixes 2 video filters and makes the env variable work

* Adds FFMPEG_RESOLUTION to all the docker-compose files

* Makes the resolution based on the longer side

* Fixes failing test
This commit is contained in:
Lukas 2023-06-29 10:07:47 +02:00 committed by GitHub
parent 2dc9e142ef
commit 19ac83dd20
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 21 additions and 47 deletions

View file

@ -109,7 +109,7 @@ services:
# PHOTOPRISM_FFMPEG_ENCODER: "nvidia" # FFmpeg encoder ("software", "intel", "nvidia", "apple", "raspberry", "vaapi") Intel: "intel" for Broadwell or later and "vaapi" for Haswell or earlier
# PHOTOPRISM_FFMPEG_ENCODER: "intel" # FFmpeg encoder ("software", "intel", "nvidia", "apple", "raspberry", "vaapi") Intel: "intel" for Broadwell or later and "vaapi" for Haswell or earlier`
# PHOTOPRISM_FFMPEG_BITRATE: "32" # FFmpeg encoding bitrate limit in Mbit/s (default: 50)
# PHOTOPRISM_FFMPEG_RESOLUTION: "1080" # FFmpeg encoding resolution limit in pixel height (default: 2160)
# PHOTOPRISM_FFMPEG_RESOLUTION: "1920" # FFmpeg encoding resolution limit in pixel height (default: 4096)
# LIBVA_DRIVER_NAME: "i965" # For Intel architectures Haswell and older which do not support QSV yet but use VAAPI instead
## Share hardware devices with FFmpeg and TensorFlow (optional):
# devices:

View file

@ -41,11 +41,9 @@ func (c *Config) FFmpegBitrate() int {
func (c *Config) FFmpegResolution() int {
switch {
case c.options.FFmpegResolution <= 0:
return 4320
case c.options.FFmpegResolution <= 144:
return 144
case c.options.FFmpegResolution >= 4320:
return 4320
return 4096
case c.options.FFmpegResolution >= 8192:
return 8192
default:
return c.options.FFmpegResolution
}
@ -81,7 +79,7 @@ func (c *Config) FFmpegMapAudio() string {
}
// FFmpegOptions returns the FFmpeg transcoding options.
func (c *Config) FFmpegOptions(encoder ffmpeg.AvcEncoder, bitrate string, resolution string) (ffmpeg.Options, error) {
func (c *Config) FFmpegOptions(encoder ffmpeg.AvcEncoder, bitrate string) (ffmpeg.Options, error) {
// Transcode all other formats with FFmpeg.
opt := ffmpeg.Options{
Bin: c.FFmpegBin(),
@ -89,7 +87,7 @@ func (c *Config) FFmpegOptions(encoder ffmpeg.AvcEncoder, bitrate string, resolu
Bitrate: bitrate,
MapVideo: c.FFmpegMapVideo(),
MapAudio: c.FFmpegMapAudio(),
Resolution: resolution,
Resolution: fmt.Sprintf("%v", c.FFmpegResolution()),
}
// Check

View file

@ -45,7 +45,7 @@ func TestConfig_FFmpegBitrate(t *testing.T) {
func TestConfig_FFmpegResolution(t *testing.T) {
c := NewConfig(CliTestContext())
assert.Equal(t, 4320, c.FFmpegResolution())
assert.Equal(t, 4096, c.FFmpegResolution())
c.options.FFmpegResolution = 1920
assert.Equal(t, 1920, c.FFmpegResolution())
@ -88,8 +88,7 @@ func TestConfig_FFmpegMapAudio(t *testing.T) {
func TestConfig_FFmpegOptions(t *testing.T) {
c := NewConfig(CliTestContext())
bitrate := "25M"
resolution := "1080"
opt, err := c.FFmpegOptions(ffmpeg.SoftwareEncoder, bitrate, resolution)
opt, err := c.FFmpegOptions(ffmpeg.SoftwareEncoder, bitrate)
assert.NoError(t, err)
assert.Equal(t, c.FFmpegBin(), opt.Bin)
assert.Equal(t, ffmpeg.SoftwareEncoder, opt.Encoder)
@ -98,5 +97,4 @@ func TestConfig_FFmpegOptions(t *testing.T) {
assert.Equal(t, ffmpeg.MapAudioDefault, opt.MapAudio)
assert.Equal(t, c.FFmpegMapVideo(), opt.MapVideo)
assert.Equal(t, c.FFmpegMapAudio(), opt.MapAudio)
assert.Equal(t, resolution, opt.Resolution)
}

View file

@ -583,7 +583,7 @@ var Flags = CliFlags{
Flag: cli.IntFlag{
Name: "ffmpeg-resolution",
Usage: "maximum FFmpeg encoding `RESOLUTION` (height)",
Value: 2160,
Value: 4096,
EnvVar: EnvVar("FFMPEG_RESOLUTION"),
}}, {
Flag: cli.StringFlag{

View file

@ -14,7 +14,7 @@ func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd,
} else if avcName == "" {
return nil, false, fmt.Errorf("empty output filename")
}
scale := "scale='if(gte(iw,ih), min(" + opt.Resolution + ", iw), -2):if(gte(iw,ih), -2, min(" + opt.Resolution + ", ih))'"
// Don't transcode more than one video at the same time.
useMutex = true
@ -25,7 +25,6 @@ func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd,
"-i", fileName,
"-movflags", "faststart",
"-pix_fmt", "yuv420p",
// "-vf", "scale='-2:trunc("+opt.Resolution+"/2)*2'",
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2",
"-f", "mp4",
"-y",
@ -49,7 +48,7 @@ func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd,
"-qsv_device", "/dev/dri/renderD128",
"-i", fileName,
"-c:a", "aac",
"-vf", "\"scale='-2:"+opt.Resolution+"',"+format+"\"",
"-vf", scale+", "+format+"",
"-c:v", opt.Encoder.String(),
"-map", opt.MapVideo,
"-map", opt.MapAudio,
@ -72,7 +71,7 @@ func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd,
"-map", opt.MapVideo,
"-map", opt.MapAudio,
"-c:a", "aac",
"-vf", "\"scale='-2:"+opt.Resolution+"',"+format+"\"",
"-vf", scale+", "+format+"",
"-profile", "high",
"-level", "51",
"-vsync", "vfr",
@ -90,7 +89,7 @@ func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd,
"-hwaccel", "vaapi",
"-i", fileName,
"-c:a", "aac",
"-vf", "\"scale='-2:"+opt.Resolution+"',"+format+"\"",
"-vf", scale+", "+format+"",
"-c:v", opt.Encoder.String(),
"-map", opt.MapVideo,
"-map", opt.MapAudio,
@ -117,7 +116,7 @@ func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd,
"-preset", "15",
"-pixel_format", "yuv420p",
"-gpu", "any",
"-vf", "\"scale='-2:"+opt.Resolution+"',"+format+"\"",
"-vf", scale+", "+format+"",
"-rc:v", "constqp",
"-cq", "0",
"-tune", "2",
@ -141,7 +140,7 @@ func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd,
"-map", opt.MapVideo,
"-map", opt.MapAudio,
"-c:a", "aac",
"-vf", "\"scale='-2:"+opt.Resolution+"',"+format+"\"",
"-vf", scale+", "+format+"",
"-num_output_buffers", "72",
"-num_capture_buffers", "64",
"-max_muxing_queue_size", "1024",
@ -163,7 +162,7 @@ func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd,
"-map", opt.MapVideo,
"-map", opt.MapAudio,
"-c:a", "aac",
"-vf", "\"scale='-2:"+opt.Resolution+"',"+format+"\"",
"-vf", scale+", "+format+"",
"-max_muxing_queue_size", "1024",
"-crf", "23",
"-vsync", "vfr",

View file

@ -149,8 +149,7 @@ func (c *Convert) AvcConvertCommand(f *MediaFile, avcName string, encoder ffmpeg
// Transcode all other formats with FFmpeg.
var opt ffmpeg.Options
if opt, err = c.conf.FFmpegOptions(encoder, c.AvcBitrate(f), c.AvcResolution(f)); err != nil {
if opt, err = c.conf.FFmpegOptions(encoder, c.AvcBitrate(f)); err != nil {
return nil, false, fmt.Errorf("convert: failed to transcode %s (%s)", clean.Log(f.BaseName()), err)
} else {
return ffmpeg.AvcConvertCommand(fileName, avcName, opt)
@ -178,24 +177,3 @@ func (c *Convert) AvcBitrate(f *MediaFile) string {
return fmt.Sprintf("%dM", bitrate)
}
// AvcResolution returns the resolution to use for transcoding.
func (c *Convert) AvcResolution(f *MediaFile) string {
const defaultResolution = "2160"
if f == nil {
return defaultResolution
}
limit := c.conf.FFmpegResolution()
resolution := f.height
if resolution <= 144 {
return defaultResolution
} else if resolution > limit {
resolution = limit
}
return fmt.Sprintf("%d", resolution)
}

View file

@ -87,7 +87,7 @@ services:
## Hardware Video Transcoding:
# PHOTOPRISM_FFMPEG_ENCODER: "raspberry" # FFmpeg encoder ("software", "intel", "nvidia", "apple", "raspberry")
# PHOTOPRISM_FFMPEG_BITRATE: "32" # FFmpeg encoding bitrate limit in Mbit/s (default: 50)
# PHOTOPRISM_FFMPEG_RESOLUTION: "1080" # FFmpeg encoding resolution limit in pixel height (default: 2160)
# PHOTOPRISM_FFMPEG_RESOLUTION: "1920" # FFmpeg encoding resolution limit in pixel height (default: 4096)
## Run as a non-root user after initialization (supported: 0, 33, 50-99, 500-600, and 900-1200):
# PHOTOPRISM_UID: 1000
# PHOTOPRISM_GID: 1000

View file

@ -78,7 +78,7 @@ services:
## Hardware Video Transcoding:
# PHOTOPRISM_FFMPEG_ENCODER: "software" # FFmpeg encoder ("software", "intel", "nvidia", "apple", "raspberry")
# PHOTOPRISM_FFMPEG_BITRATE: "32" # FFmpeg encoding bitrate limit in Mbit/s (default: 50)
# PHOTOPRISM_FFMPEG_RESOLUTION: "1080" # FFmpeg encoding resolution limit in pixel height (default: 2160)
# PHOTOPRISM_FFMPEG_RESOLUTION: "1920" # FFmpeg encoding resolution limit in pixel height (default: 4096)
## Run as a non-root user after initialization (supported: 0, 33, 50-99, 500-600, and 900-1200):
# PHOTOPRISM_UID: 1000
# PHOTOPRISM_GID: 1000

View file

@ -83,7 +83,7 @@ services:
## see https://docs.photoprism.app/getting-started/advanced/transcoding/#nvidia-container-toolkit
PHOTOPRISM_FFMPEG_ENCODER: "nvidia"
PHOTOPRISM_FFMPEG_BITRATE: "50"
PHOTOPRISM_FFMPEG_RESOLUTION: "2160"
PHOTOPRISM_FFMPEG_RESOLUTION: "4096"
NVIDIA_VISIBLE_DEVICES: "all"
NVIDIA_DRIVER_CAPABILITIES: "compute,video,utility"
## Run as a non-root user after initialization (supported: 0, 33, 50-99, 500-600, and 900-1200):

View file

@ -82,6 +82,7 @@ services:
## Hardware Video Transcoding:
# PHOTOPRISM_FFMPEG_ENCODER: "software" # FFmpeg encoder ("software", "intel", "nvidia", "apple", "raspberry")
# PHOTOPRISM_FFMPEG_BITRATE: "32" # FFmpeg encoding bitrate limit in Mbit/s (default: 50)
# PHOTOPRISM_FFMPEG_RESOLUTION: "1920" # FFmpeg encoding resolution limit in pixel (default: 4096)
## Run as a non-root user after initialization (supported: 0, 33, 50-99, 500-600, and 900-1200):
# PHOTOPRISM_UID: 1000
# PHOTOPRISM_GID: 1000