So you want to convert a GIF


by

I tried to convert GIF to video in a blog post. It did not go well.

Video

The unoptimized web page with FOIT has 5 frames, because the site is repainted every time each of the three web fonts are loaded.
The optimized web page without FOIT has 3 frames, 2 fewer, because the site is is only repainted once all three web fonts have been loaded.
<figure aria-labelledby="fig-cap-vid1" role="group">
    <video loop controls poster="/assets/blog/web-fonts/with-foit.jpg" preload="none">
        <source type="video/mp4"
                src="/assets/blog/web-fonts/with-foit.mp4" />
        <source type="video/webm"
                src="/assets/blog/web-fonts/with-foit.webm" />
        <source type="video/ogg"
                src="/assets/blog/web-fonts/with-foit.ogv" />
        <p>This shows an animated timelapse of loading with FOIT. Only the final frame has a readable web page at 3.5s. View <a href="/assets/blog/web-fonts/with-foit.gif">the GIF</a>.</p>
    </video>
    <figcaption id="fig-cap-vid1">The unoptimized web page with FOIT has <strong>5 frames</strong>, because the site is repainted every time each of the three web fonts are loaded.</figcaption>
</figure>
<figure aria-labelledby="fig-cap-vid2" role="group">
    <video loop controls poster="/assets/blog/web-fonts/without-foit.jpg" preload="none">
        <source type="video/mp4"
                src="/assets/blog/web-fonts/without-foit.mp4" />
        <source type="video/webm"
                src="/assets/blog/web-fonts/without-foit.webm" />
        <source type="video/ogg"
                src="/assets/blog/web-fonts/without-foit.ogv" />
        This shows an animated timelapse of loading unoptimized web page with FOIT. The web page is readable from 1.3s and renders the page with the web font at 2.3s. View <a href="/assets/blog/web-fonts/without-foit.gif">the GIF</a>.</p>
    </video>
    <figcaption id="fig-vid2">The optimized web page without FOIT has <strong>3 frames</strong>, 2 fewer, because the site is is only repainted once <em>all</em> three web fonts have been loaded.</figcaption>
</figure>

The video files were created thusly:

ffmpeg -i example.gif -c:v libvpx -crf 12 -b:v 500K example.webm
ffmpeg -i example.webm -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" example.mp4
ffmpeg -i example.webm example.ogv

Errors

  • In mobile Safari, the videos have artifacts (old conversion).
  • In mobile Safari, videos won’t load at all, when you visit the direct link (ffmpeg conversion).
  • In Chrome, frames are missing (old version).
  • In Chrome and desktop Safari, the fallback doesn’t work, when only an unsupported video type is available.
  • In Chrome, the MP4 is not shown, and the browser skips to the next format; both files are loaded, though.
  • In Chrome, the latter video (without-foit.webm) is missing the last of the three frames of the GIF.

So for now, the MP4 file is somehow bugged; could be that the offender is

ffmpeg -i example.webm -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" example.mp4

Add to this that the Skeleton CSS framework does not seem to support <video> tags, which break the layout.

Debug info

$ ffmpeg --version
ffmpeg version 2.8.2 Copyright (c) 2000-2015 the FFmpeg developers
  built with Apple LLVM version 7.0.0 (clang-700.1.76)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/2.8.2 \
    --enable-shared \
    --enable-pthreads \
    --enable-gpl \
    --enable-version3 \
    --enable-hardcoded-tables \
    --enable-avresample \
    --cc=clang \
    --host-cflags= \
    --host-ldflags= \
    --enable-opencl \
    --enable-libx264 \
    --enable-libmp3lame \
    --enable-libvo-aacenc \
    --enable-libxvid \
    --enable-libtheora \
    --enable-libvorbis \
    --enable-libvpx \
    --enable-vda
  libavutil      54. 31.100 / 54. 31.100
  libavcodec     56. 60.100 / 56. 60.100
  libavformat    56. 40.101 / 56. 40.101
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 40.101 /  5. 40.101
  libavresample   2.  1.  0 /  2.  1.  0
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  2.101 /  1.  2.101
  libpostproc    53.  3.100 / 53.  3.100
$ ffprobe assets/blog/web-fonts/with-foit.webm
ffprobe version 2.8.2 Copyright (c) 2007-2015 the FFmpeg developers
  built with Apple LLVM version 7.0.0 (clang-700.1.76)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/2.8.2 \
    --enable-shared \
    --enable-pthreads \
    --enable-gpl \
    --enable-version3 \
    --enable-hardcoded-tables \
    --enable-avresample \
    --cc=clang \
    --host-cflags= \
    --host-ldflags= \
    --enable-opencl \
    --enable-libx264 \
    --enable-libmp3lame \
    --enable-libvo-aacenc \
    --enable-libxvid \
    --enable-libtheora \
    --enable-libvorbis \
    --enable-libvpx \
    --enable-vda
  libavutil      54. 31.100 / 54. 31.100
  libavcodec     56. 60.100 / 56. 60.100
  libavformat    56. 40.101 / 56. 40.101
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 40.101 /  5. 40.101
  libavresample   2.  1.  0 /  2.  1.  0
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  2.101 /  1.  2.101
  libpostproc    53.  3.100 / 53.  3.100
Input #0, matroska,webm, from 'assets/blog/web-fonts/with-foit.webm':
  Metadata:
    encoder         : Lavf56.40.101
  Duration: 00:00:03.75, start: 0.000000, bitrate: 32 kb/s
    Stream #0:0: Video: vp8, yuv420p, 506x325, SAR 1:1 DAR 506:325, \
    1.33 fps, 1.33 tbr, 1k tbn, 1k tbc (default)
    Metadata:
      alpha_mode      : 1
$ ffprobe assets/blog/web-fonts/with-foit.mp4
ffprobe version 2.8.2 Copyright (c) 2007-2015 the FFmpeg developers
  built with Apple LLVM version 7.0.0 (clang-700.1.76)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/2.8.2 \
    --enable-shared \
    --enable-pthreads \
    --enable-gpl \
    --enable-version3 \
    --enable-hardcoded-tables \
    --enable-avresample \
    --cc=clang \
    --host-cflags= \
    --host-ldflags= \
    --enable-opencl \
    --enable-libx264 \
    --enable-libmp3lame \
    --enable-libvo-aacenc \
    --enable-libxvid \
    --enable-libtheora \
    --enable-libvorbis \
    --enable-libvpx \
    --enable-vda
  libavutil      54. 31.100 / 54. 31.100
  libavcodec     56. 60.100 / 56. 60.100
  libavformat    56. 40.101 / 56. 40.101
  libavdevice    56.  4.100 / 56.  4.100
  libavfilter     5. 40.101 /  5. 40.101
  libavresample   2.  1.  0 /  2.  1.  0
  libswscale      3.  1.101 /  3.  1.101
  libswresample   1.  2.101 /  1.  2.101
  libpostproc    53.  3.100 / 53.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'assets/blog/web-fonts/with-foit.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf56.40.101
  Duration: 00:00:03.75, start: 0.000000, bitrate: 44 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), \
      yuv420p, 506x324 [SAR 324:325 DAR 506:325], 42 kb/s, 1.33 fps, \
      1.33 tbr, 16384 tbn, 2.67 tbc (default)
    Metadata:
      handler_name    : VideoHandler

Baaack to images

Since the reason I converted the GIFs in the first place was to save bandwidth, I ended up going with a simple PNG thumbnail linking to the GIFs.

This shows an animated timelapse of loading with FOIT. Only the final frame has a readable web page at 3.5s
The unoptimized web page with FOIT has 5 frames, because the site is repainted every time each of the three web fonts are loaded.
This shows an animated timelapse of loading unoptimized web page with FOIT. The web page is readable from 1.3s and renders the page with the web font at 2.3s.
The optimized web page without FOIT has 3 frames, 2 fewer, because the site is is only repainted once all three web fonts have been loaded.
<figure aria-labelledby="fig-cap-gif1" role="group">
    <a href="/assets/blog/web-fonts/with-foit.gif"><img alt="This shows an animated timelapse of loading with FOIT. Only the final frame has a readable web page at 3.5s" src="/assets/blog/web-fonts/with-foit.jpg" /></a>
    <figcaption id="fig-cap-gif1">The unoptimized web page with FOIT has <strong>5 frames</strong>, because the site is repainted every time each of the three web fonts are loaded.</figcaption>
</figure>
<figure aria-labelledby="fig-cap-gif2" role="group">
    <a href="/assets/blog/web-fonts/without-foit.gif"><img alt="This shows an animated timelapse of loading unoptimized web page with FOIT. The web page is readable from 1.3s and renders the page with the web font at 2.3s." src="/assets/blog/web-fonts/without-foit.jpg" /></a>
    <figcaption id="fig-cap-gif2">The optimized web page without FOIT has <strong>3 frames</strong>, 2 fewer, because the site is is only repainted once <em>all</em> three web fonts have been loaded.</figcaption>
</figure>

Where the videos were 1/5 the size of the GIFs, the thumbnails were 1/10.

I still need to figure out how the hell you’re supposed to make this work, though.