Converting
Convert GIF to MP4 on Mac
The command is one line: ffmpeg -i in.gif -c:v libx264 -crf 23 -pix_fmt yuv420p -movflags +faststart out.mp4. Install it with brew install ffmpeg. There is no built-in macOS route and no good reason to look for one.
The size difference is larger than the usual “about ten times” claim, and it depends on content. A 4-second 480 × 320 photographic GIF measured 8,687,717 bytes. The same frames as H.264 at CRF 23 came to 259,669 bytes. That is 33.5 times smaller. A mostly-static screen recording only improved 2.5 times, and knowing which case you have is the point of this page.
How much bigger is a GIF than the same content as video?
Two clips, both encoded from identical source frames so nothing is confounded. The GIFs were built with ffmpeg’s two-pass palettegen and paletteuse with Floyd–Steinberg dithering, which is the good way to make a GIF. A naive single-palette GIF of the same frames came out slightly larger, so these numbers flatter GIF rather than the reverse.
| Clip | GIF | H.264 CRF 23 | H.264 CRF 28 | H.265 CRF 28 | VP9 WebM |
|---|---|---|---|---|---|
| UI recording, 1280 × 800, 5.0 s | 183,238 B | 72,948 B (2.5×) | 61,803 B (3.0×) | 77,336 B (2.4×) | 61,504 B (3.0×) |
| Photo pan, 480 × 320, 4.0 s | 8,687,717 B | 259,669 B (33.5×) | 130,481 B (66.6×) | 152,065 B (57.1×) | not measured |
Expressed as bitrate the photographic GIF is absurd. 8,687,717 bytes over 4 seconds is 17,375 kbps, at 480 × 320. That is a higher data rate than most 1080p streaming, for a clip the size of a postage stamp. H.264 carried the same footage at 519 kbps.
The mechanism is simple and it is worth understanding rather than memorising the ratio. GIF has a 256-colour palette per frame and lossless LZW compression along scanlines. It has no transform coding and no motion compensation, so nothing can be predicted from the frame before. When the whole picture shifts, as it does in a camera pan, every frame is effectively new. It is not dithering that does the damage either: re-encoding the same clip with dithering disabled saved only 2.8%, from 8,687,717 to 8,447,548 bytes.
That also explains the 2.5× figure on the UI recording. A dashboard with a moving progress bar leaves most pixels untouched frame to frame, and GIF’s frame-difference blocks handle that reasonably. GIF is not catastrophic for flat, static screen content. It is catastrophic for anything that moves or was ever a photograph.
What is the right ffmpeg command for the web?
Four flags matter and the rest is noise.
ffmpeg -i in.gif \
-movflags +faststart \
-pix_fmt yuv420p \
-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" \
-c:v libx264 -crf 23 -preset slow \
out.mp4-movflags +faststart moves the index to the front of the file so playback starts before the whole thing downloads. Without it a browser may buffer the entire clip first.
-pix_fmt yuv420p is not optional. Leave it out and ffmpeg may pick a pixel format that QuickTime and Safari will not decode, and you will get a black rectangle with no error.
The scale filter is there because H.264 requires even dimensions and GIFs frequently are not. Feeding a 481 × 321 GIF straight to libx264 produces width not divisible by 2 (481x321) and no output file. The trunc expression rounds both axes down to the nearest even number, which cost one pixel of width and one of height in testing.
-crf is the quality dial, lower being better, sane range 18 to 28. CRF 23 is a good default for screen content; 28 halved the file on both test clips and is fine for a background loop nobody studies. The same dial and its behaviour are covered in more depth in reducing video file size without wrecking it.
Use libx264 rather than libx265 for anything going on the web. H.265 was larger than H.264 at the same CRF on both clips here, and its browser support is narrower.
How do you make an MP4 behave like a GIF in HTML?
A GIF autoplays and loops with no attributes. An MP4 needs four, and missing one of them is the usual reason a replacement “does not work”.
<video
src="demo.mp4"
autoplay
loop
muted
playsinline
width="1280" height="800"
preload="metadata"
></video>muted is the one people forget. Chrome and Safari both block autoplay for anything with audio unless the user has interacted with the page, and both explicitly allow muted autoplay. Chrome’s policy is documented at developer.chrome.com/blog/autoplay; WebKit’s is at webkit.org/blog/6784. Note that muted has to be the attribute, not a property you set later in JavaScript, because the autoplay decision is made when the element is parsed.
playsinline is the iPhone one. Without it, Safari on iOS takes a video element full screen when it starts playing, which is a disaster for a decorative loop sitting in a paragraph.
width and height stop the page reflowing when the video loads, the same reason you set them on an img. And preload="metadata" keeps the browser from pulling the whole file before it is scrolled into view.
One consequence worth planning for: a muted video has no audio, so if the original GIF was a clip from something with dialogue, an MP4 replacement silently drops it. That is normally what you want and occasionally not.
How do you convert a folder of GIFs at once?
A loop, and it is genuinely all you need:
cd ~/path/to/gifs
for f in *.gif; do
ffmpeg -nostdin -v error -i "$f" \
-movflags +faststart -pix_fmt yuv420p \
-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" \
-c:v libx264 -crf 23 -preset slow "${f%.gif}.mp4"
done-nostdin matters in a loop. Without it ffmpeg consumes stdin and the loop eats its own file list after the first iteration.
Where an app earns its place is the step after this one: taking the MP4s ffmpeg produced and making WebM copies for the source fallback, or compressing a folder of finished clips to a target. Smol converted two MP4s to WebM in 3,148 ms. One caution from that run, and it is the same lesson as transcoding AVIF to JPG: both WebM files came out larger than the H.264 they were made from, by 147.4% and 28.4%. Encode each delivery format from the original frames, not from another encode.
When Smol is not the answer
For this job, always. Smol does not convert animated GIFs, and we would rather say so here than have you find out after paying.
Tested on 2026-09-26 against Smol 1.0.34: all three test GIFs failed a GIF to MP4 conversion with “This file couldn’t be processed. It may be corrupted or in an unsupported format.” An animated GIF to PNG failed as well. A single-frame GIF to PNG succeeded in 227 ms. The app’s own diagnostic reported a healthy install with every bundled encoder present, so this is a real boundary and not a local fault: Smol treats GIF as a still-image format.
It will compress an animated GIF while keeping it a GIF, and the numbers argue against bothering. The photographic GIF went from 8,687,717 to 7,973,928 bytes, a saving of 8.2%. The UI GIF came back untouched with the note already optimized. Against H.264’s 33.5×, an 8% GIF-to-GIF saving is not a solution to anything.
So: ffmpeg for the conversion. If you would rather not touch a Terminal, Gifski and Permute both have Mac front ends for this, and HandBrake will do it if you already have it open, at the cost of its settings maze.
Smol is worth having for the surrounding work: batch-compressing the finished MP4s, producing WebM alternates, and the other conversions in this cluster, which include PNG to WebP, batch HEIC to JPG and M4A to MP3. The full list is in the format reference, and it is $29 once if that set is your workload. Converting one GIF is not.
Frequently asked questions
How do I convert a GIF to MP4 on a Mac?
Install ffmpeg with brew install ffmpeg, then run: ffmpeg -i in.gif -c:v libx264 -crf 23 -pix_fmt yuv420p -movflags +faststart out.mp4. There is no built-in macOS command for this. Add -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" if the GIF has odd pixel dimensions.
How much smaller is an MP4 than a GIF?
It depends on the content. A 4-second 480 by 320 photographic GIF measured 8,687,717 bytes against 259,669 bytes for the same frames as H.264 at CRF 23, which is 33.5 times smaller. A 5-second mostly-static screen recording improved only 2.5 times, from 183,238 to 72,948 bytes.
Why does my MP4 not autoplay like the GIF did?
It is almost certainly missing the muted attribute. Chrome and Safari block autoplay for video with audio until the user interacts with the page, and both allow muted autoplay. Use autoplay, loop, muted and playsinline together. The muted attribute must be in the markup, not set later from JavaScript.
What does playsinline do on a video element?
It stops Safari on iOS from taking the video full screen the moment it starts playing. Without playsinline, a decorative looping clip inside an article hijacks the whole screen on an iPhone. It has no effect on desktop browsers, so there is no reason to leave it out.
Can Smol convert an animated GIF to MP4?
No. Tested on 26 September 2026 against Smol 1.0.34, three animated GIFs all failed with "This file couldn’t be processed. It may be corrupted or in an unsupported format." Smol treats GIF as a still-image format. It will compress an animated GIF in place, but that saved only 8.2% against 33.5 times for H.264. Use ffmpeg.
Keep reading