Youtube Video to Giphy

ffmpeg
Youtube
CLI
Author

im@johnho.ca

Published

Wednesday, April 16, 2025

Abstract
how to use yt-dlp with ffmpeg to create a gif and host it for free

introduction

Back in 2020 Firefox write a blog post which introduced a series of relaxing video meant to be played in a loop in the (then) new “picture-in-picture” mode.

Here’s an example:

Source Video: Relaxing Forest

Figure 1

yt-dlp

yt-dlp is a CLI to download video but you could also pipe the video as stream straight into ffmpeg:

yt-dlp -f "bv*[ext=mp4][height<1080]" "https://youtu.be/r45aZe_OtuM?si=Ta58dCZTI4QCrerG" -o - \
    | ffmpeg -i pipe:0 -c copy output.mp4
  • one of the best thing about yt-dlp is the filter for expressively picking the right stream to download1. Here with -f "bv*[ext=mp4][height<1080]" we are selecting the best quality mp4 stream that’s less than 1080 pixel in height
  • the -o - option tells yt-dlp to write the outputs to stdout
  • to read the output from yt-dlp in ffmpeg, we need the option -i pipe:0

gifski

gifski makes the highest quality GIFs. Think of it as the opposite of gifsicle which is great for compressing GIFs.

How much better?

(a) without gifski
(b) with gifski
Figure 2: gifski demo

The best part is that gifski play nicely with ffmpeg also. Let’s say I want to crop a gif while keeping the highest quality:

ffmpeg -i  source.gif -vf "crop=iw:ih*0.9:0:0" -pix_fmt yuv420p -f yuv4mpegpipe -
    | gifski -o output.gif -
  • in ffmpeg we use -f yuv4mpegpipe - to format the output properly to stdout for gifski
  • for gif input source, you will need to specify the pixel format with -pix_fmt yuv420p for ffmpeg to figure out how to combine with -f yuv4mpegpipe -

yt-dlp to ffmpeg to gifski

okay so to create the highest quality 5-second gif from Figure 1 without having to download the video:

yt-dlp -f "bv*[ext=mp4][height<1080]" "https://youtu.be/r45aZe_OtuM?si=Ta58dCZTI4QCrerG" -o - \
    | ffmpeg -i pipe:0 -ss 10 -t 5 -vf "crop=iw:ih*0.85:0:0" -f yuv4mpegpipe - \
    | gifski -o tree.gif -
  • since the input to ffmpeg is a stream the -ss 10 option has to come after the input, otherwise you might run into the “partial file” error
  • our filter -vf "crop=iw:ih*0.85:0:0" crop out the bottom 15% of the frame

“Hosting” on giphy

the last step is to “host” it on giphy.

Our uploaded tree.gif lives at https://giphy.com/gifs/da0KMpaD7t6psYvV3Y

But that’s just a link to a page on giphy. To get the actual gif URL is more complicated, but thanks to Eric’s tip we know that the gif URL format is:

https://i.giphy.com/media/{gif_hash}/giphy.gif

So for our tree.gif it would be https://i.giphy.com/media/da0KMpaD7t6psYvV3Y/giphy.gif

Figure 3: Our Tree GIF on giphy!

Footnotes

  1. there’s bit of a learning curve, best to start with their examples here↩︎