Gable speeds through a host of haunts!
Quest for the realtime gif
In the course of adding and creating elements for the website, I realized I should have a gif to go with the explanation of the Hourglass speed-run game modes. I soon encountered an unexpected complication.
I recorded a gif with my typical recording workflow, and as is always the case, the gif playback was a bit slower than realtime. This is partly due to a quirk of the gif file format, and usually this doesn’t really bother me. But in this case, the whole point of this gif/video is to demonstrate the in-game timer, and so I don’t want the timer to appear to be running at the wrong speed, just because the gif itself is playing back at the wrong speed.
I can’t just add a note to the site explaining gif quirkiness to visitors; I need the video to play at the correct speed to begin with.
This gif quirkiness is interesting, and a product of the format’s history, which I’ll explain a bit of at the end of the post.
Approaching realtime
So, I tried re-recording with different capture and playback frame rates, to try for a closer to realtime final result. I got a recording that played back at nearly realtime speed. This is when I encountered the second issue.
For the website, I convert all the gifs to mp4 videos. (There are some interesting reasons for this I’ll cover in an upcoming post.) The converted mp4s inherit the slightly non-realtime playback speed of the gifs.
The problem my Hourglass video had now, was that the mp4 videos have a time seek bar at the bottom, which shows the video time at the current position. So, when I play the video, the in-game timer and the video seek bar time start together, and go out of synch. Not by a lot, only about two seconds by the end, but it means that almost realtime playback still isn’t quite good enough. With the seek bar for comparison, the in-game timer will once again appear wrong because, even though the playback speed of the newer video was closer to realtime, it’s still slightly off.
At this point I wanted the video to be as close to realtime as possible, so that the in-game and video timers would match for the entire video length.
Actual realtime & the recorder bug
I did some math based on the capture frame-rate and allowed gif playback frame rates, recorded a new video, and the result was still not matching, which really confused me. After trying a bunch of different recording settings, it finally began to dawn on me that the program I was using to record the gifs, was actually recording at a slightly different frame rate than the rate it indicated it was set to.
As a test, I recorded at 10 fps for 60 seconds, expecting to get 600 frames, but instead I got 548 frames. It was capturing at about 91% the speed it was set to.
That is, when set to 10 fps, the program was actually capturing at 9.1333 fps.
With this knowledge, I scaled the capture speed by 91%, re-recorded the video one last time, and finally the in-game and mp4 video timers matched!
Gif quirkiness
Animated gifs were initially meant to enable simple low-speed animations on the web. Like a blinking arrow, rotating globe, or rows upon rows of intensely sparkling cats with butterfly wings.
Early on, gifs animations were fairly simple, with a sparse frame count. To determine playback speed, you set the display time for each individual frame, instead of specifying a fixed frame rate for the entire animation. This meant that you could do things like make a single frame hold for a long time, then play a quick animation, then loop back to the long hold frame.
So you might think that if you want a 60 fps gif, you can tell each frame to display for 1/60th of a second. Unfortunately, in gifs, this frame display time can only have two decimal places of precision. (e.g. 1.00)
1/60 = 0.016666…
We could round it up to 0.02, but that’s 50 fps. We could round down to 0.01 but that’s 100 fps. (and also to my knowledge, no browser will play a gif at 100 fps.)
I usually go with 0.02, or 0.03.
Basically all the high frame rates you might want to use, run up against this two decimal place limit.
So your options are a little weird:
- [Display time] = [Equivalent frame rate]
- 0.02 = 50 fps
- 0.03 = 33.3333… fps
- 0.04 = 25 fps
- 0.05 = 20 fps
- 0.06 = 16.6666… fps
- 0.07 = 14.2857…
- etc…
This is why if you record a gif at 60 fps, you can’t play it back at 60 fps.
But you can import the frames into a video editor and force them to play at the correct speed.
(Note: After starting the video below, you can right click it and enable “Loop” to make it loop like a gif.)
Hope you’re all doing well. 🙂