diff --git a/docker-compose.yml b/docker-compose.yml index f34f8971c..bd1f02c34 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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: diff --git a/internal/config/config_ffmpeg.go b/internal/config/config_ffmpeg.go index 5f034c535..f4cc54d81 100644 --- a/internal/config/config_ffmpeg.go +++ b/internal/config/config_ffmpeg.go @@ -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 diff --git a/internal/config/config_ffmpeg_test.go b/internal/config/config_ffmpeg_test.go index 2eec24aaa..6a8540627 100644 --- a/internal/config/config_ffmpeg_test.go +++ b/internal/config/config_ffmpeg_test.go @@ -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) } diff --git a/internal/config/flags.go b/internal/config/flags.go index e171f94f1..8db8bb25f 100644 --- a/internal/config/flags.go +++ b/internal/config/flags.go @@ -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{ diff --git a/internal/ffmpeg/convert.go b/internal/ffmpeg/convert.go index 30e789bc4..405673b36 100644 --- a/internal/ffmpeg/convert.go +++ b/internal/ffmpeg/convert.go @@ -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", diff --git a/internal/photoprism/convert_video_avc.go b/internal/photoprism/convert_video_avc.go index c4a712e24..c6992542c 100644 --- a/internal/photoprism/convert_video_avc.go +++ b/internal/photoprism/convert_video_avc.go @@ -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) -} diff --git a/setup/docker/arm64/docker-compose.yml b/setup/docker/arm64/docker-compose.yml index 5bf04423c..790036998 100644 --- a/setup/docker/arm64/docker-compose.yml +++ b/setup/docker/arm64/docker-compose.yml @@ -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 diff --git a/setup/docker/docker-compose.yml b/setup/docker/docker-compose.yml index 8e2579701..9ba336eb9 100644 --- a/setup/docker/docker-compose.yml +++ b/setup/docker/docker-compose.yml @@ -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 diff --git a/setup/docker/nvidia/docker-compose.yml b/setup/docker/nvidia/docker-compose.yml index 6d61cd64a..e5936194d 100644 --- a/setup/docker/nvidia/docker-compose.yml +++ b/setup/docker/nvidia/docker-compose.yml @@ -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): diff --git a/setup/podman/docker-compose.yml b/setup/podman/docker-compose.yml index d14e8c1fb..24299ecb7 100644 --- a/setup/podman/docker-compose.yml +++ b/setup/podman/docker-compose.yml @@ -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