posts: fix calculation of animated PNG duration.
Fix certain animated PNGs returning NaN as the duration because the frame rate was being reported as "0/0" by FFMpeg. This happens when the animation has zero delay between frames. This is supposed to mean a PNG with an infinitely fast frame rate, but in practice browsers limit it to around 10FPS. The exact frame rate browsers will use is unknown and implementation defined.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
BIN
test/files/test-animated-inf-fps.png
Normal file
BIN
test/files/test-animated-inf-fps.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 212 KiB |
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user