diff --git a/app/logical/ffmpeg.rb b/app/logical/ffmpeg.rb index 07e43147f..2628f3e6d 100644 --- a/app/logical/ffmpeg.rb +++ b/app/logical/ffmpeg.rb @@ -59,10 +59,18 @@ class FFmpeg end end + # @return [Float, nil] The frame rate of the video or animation, or nil if + # unknown. The frame rate can be unknown for animated PNGs that have zero + # delay between frames. def frame_rate rate = video_streams.first[:avg_frame_rate] # "100/57" numerator, denominator = rate.split("/") - (numerator.to_f / denominator.to_f) + + if numerator.to_f == 0 || denominator.to_f == 0 + nil + else + (numerator.to_f / denominator.to_f) + end end def video_streams diff --git a/app/logical/media_file/image.rb b/app/logical/media_file/image.rb index 1734e16bc..70a275b95 100644 --- a/app/logical/media_file/image.rb +++ b/app/logical/media_file/image.rb @@ -61,8 +61,9 @@ class MediaFile::Image < MediaFile if is_animated_gif? frame_count / duration elsif is_animated_png? - # XXX we have to resort to ffprobe to get the frame rate because libvips and exiftool can't get it. - video.frame_rate + # XXX As with GIFs, animated PNGs can have an unspecified frame rate. + # Assume 10FPS if the frame rate is unspecified. + video.frame_rate.presence || 10.0 else nil end diff --git a/test/files/test-animated-inf-fps.png b/test/files/test-animated-inf-fps.png new file mode 100644 index 000000000..5e6c0f709 Binary files /dev/null and b/test/files/test-animated-inf-fps.png differ diff --git a/test/unit/media_file_test.rb b/test/unit/media_file_test.rb index 9943124bd..866fd6756 100644 --- a/test/unit/media_file_test.rb +++ b/test/unit/media_file_test.rb @@ -263,6 +263,18 @@ class MediaFileTest < ActiveSupport::TestCase end end + context "that is animated but with an unspecified frame rate" do + should "have an assumed frame rate of 10FPS" do + file = MediaFile.open("test/files/test-animated-inf-fps.png") + + assert_equal(false, file.is_corrupt?) + assert_equal(true, file.is_animated?) + assert_equal(0.2, file.duration) + assert_equal(2, file.frame_count) + assert_equal(10, file.frame_rate) + end + end + context "that is animated but malformed" do should "be handled correctly" do file = MediaFile.open("test/files/apng/iend_missing.png")