about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorClaire <claire.github-309c@sitedethib.com>2022-02-22 17:11:22 +0100
committerGitHub <noreply@github.com>2022-02-22 17:11:22 +0100
commit166f6e4b500dd84eeffdbf887b2dc21e6d8c0aa6 (patch)
tree15940b2d096655d585f3b31d45874fe99eeeb63b /lib
parent51e67f3243d5709361bde722f341b8a5e74d63ca (diff)
Fix some media attachments being converted with too high framerates (#17619)
Video files with variable framerates are converted to constant framerate videos
and the output framerate picked by ffmpeg is based on the original file's
container framerate (which can be different from the average framerate).

This means that an input video with variable framerate with about 30 frames per
second on average, but a maximum of 120 fps will be converted to a constant 120
fps file, which won't be processed by other Mastodon servers.

This commit changes it so that input files with VFR and a maximum framerate
above the framerate threshold are converted to VFR files with the maximum frame
rate enforced.
Diffstat (limited to 'lib')
-rw-r--r--lib/paperclip/transcoder.rb16
1 files changed, 15 insertions, 1 deletions
diff --git a/lib/paperclip/transcoder.rb b/lib/paperclip/transcoder.rb
index ec1305038..afd9f58ff 100644
--- a/lib/paperclip/transcoder.rb
+++ b/lib/paperclip/transcoder.rb
@@ -13,6 +13,7 @@ module Paperclip
       @time                = options[:time] || 3
       @passthrough_options = options[:passthrough_options]
       @convert_options     = options[:convert_options].dup
+      @vfr_threshold       = options[:vfr_frame_rate_threshold]
     end
 
     def make
@@ -41,6 +42,11 @@ module Paperclip
       when 'mp4'
         @output_options['acodec'] = 'aac'
         @output_options['strict'] = 'experimental'
+
+        if high_vfr?(metadata) && !eligible_to_passthrough?(metadata)
+          @output_options['vsync'] = 'vfr'
+          @output_options['r'] = @vfr_threshold
+        end
       end
 
       command_arguments, interpolations = prepare_command(destination)
@@ -88,13 +94,21 @@ module Paperclip
     end
 
     def update_options_from_metadata(metadata)
-      return unless @passthrough_options && @passthrough_options[:video_codecs].include?(metadata.video_codec) && @passthrough_options[:audio_codecs].include?(metadata.audio_codec) && @passthrough_options[:colorspaces].include?(metadata.colorspace)
+      return unless eligible_to_passthrough?(metadata)
 
       @format          = @passthrough_options[:options][:format] || @format
       @time            = @passthrough_options[:options][:time]   || @time
       @convert_options = @passthrough_options[:options][:convert_options].dup
     end
 
+    def high_vfr?(metadata)
+      @vfr_threshold && metadata.r_frame_rate && metadata.r_frame_rate > @vfr_threshold
+    end
+
+    def eligible_to_passthrough?(metadata)
+      @passthrough_options && @passthrough_options[:video_codecs].include?(metadata.video_codec) && @passthrough_options[:audio_codecs].include?(metadata.audio_codec) && @passthrough_options[:colorspaces].include?(metadata.colorspace)
+    end
+
     def update_attachment_type(metadata)
       @attachment.instance.type = MediaAttachment.types[:gifv] unless metadata.audio_codec
     end