Sometimes we make videos but want them as an image, or sometimes we make videos but are obliged to upload images instead. The solution to this is converting the video to GIF (Graphics Interchange Format). GIF is a lossless format for image files that supports both animated and static images. In this tutorial, we will be showing how to convert a video into an GIF with React.
Prerequisites
To follow this tutorial, you need the following pre-requisites:
- Basic knowledge of JavaScript.
- Understanding of Reactjs.
The complete code is here on Codesandbox.
Getting Started
Firstly, setup a react app. To do so, paste the command below; ensure you have npm and node installed.
1npx create-react-app video-to-gif
Next is to run the application; run the command below to run the app.
1npm start
Navigate to your browser on localhost:3000, and you should have the default react page displayed.
Installing Packages
Now that react is set up, navigate to your terminal and run the command below to install the packages used in converting and downloading the video to gif.
1npm install @ffmpeg/ffmpeg@0.9.8 @ffmpeg/core@0.9.0 file-saver
Ensure you install these specific versions of @ffmpeg/ffmpeg
and @ffmpeg/core
as the latest versions has issues we won’t deal with in this tutorial.
Implementing the Video to GIF converter
Next is to make changes to App.js
file. Open the file and add the code snippet below.
1//App.js2import React, { useEffect,useState } from "react"3import './App.css';4import { createFFmpeg, fetchFile } from "@ffmpeg/ffmpeg";5import { saveAs } from "file-saver";67const ffmpeg = createFFmpeg({ log: true });89function App() {10 const [video, setVideo] = useState();11 const [name, setName] = useState()1213 const init= async () => {14 await ffmpeg.load();15 };16 const setvid = (e)=>{17 setVideo(e.target.files?.item(0))18 setName(e.target.files[0].name)19 }20useEffect(() => {21 init();22}, []);2324return (25 <div className="App">26 <header className="App-header">27 {video && (28 <video controls width="250" src={URL.createObjectURL(video)}></video>29 )}30 <input type="file" onChange={(e)=>setvid(e)}/>31 </header>32 </div>33)34}35export default App;
We first declare the ffmpeg
using the createffmpeg
method and set the log to true to allow us to log the processes. We then make use of the following :
- useEffect ****to call the
init()
, which loads theffmpeg
using theFF``mpeg.load()
function.
- the onChange event handler is triggered when you select the video to convert. It also triggers the
setvid()
, which sets the state for the name of the file and sets the video to be rendered within the return method.
Note: sometimes, we might run into an error “S**haredArrayBufffer** is not defined" don't panic, as this is due to SharedArrayBuffer being only available to pages that are cross-origin isolated.
To fix that, click the link below.
https://github.com/gzuidhof/coi-serviceworker
- Download
coi-serviceworker.js
(orcoi-serviceworker.min.js
). - Put it in the public folder
- Add this to the
index.html
file:
1<script src="coi-serviceworker.min.js"></script>
Save and start the app server with npm run start
. You should get something like this:
Click on the Choose file button and upload a video. You should get something like this:
Now that the video is rendered let's update the App.js
file with the conversion functionality.
First, add this button
below header
. The button will trigger the function that converts the video to a gif
1//App.js2...3const init = async () => {4 await ffmpeg.load();5};67const convertToGif = async () => {8 await ffmpeg.FS('writeFile', name, await fetchFile(video));9 await ffmpeg.run('-i', name, '-t', '2.5', '-ss', '2.0', '-f', 'gif', 'output.gif');10 const data = ffmpeg.FS('readFile', 'output.gif');11 const url = URL.createObjectURL(12 new Blob([data.buffer], { type: 'image/gif' }),13 );14 saveAs(url, "output.gif");15};16 ...17return(18 <header>19 ...20 </header>21 <button onClick={convertToGif}>Download and Convert to GIF</button>22 ...23)
Let’s break the code snippet above into chunks.
**convertToGif()**
: this function is triggered after uploading the video. It allows you to download the converted file. Let’s go through some of the methods in this function.
One thing to keep in mind is the use of Web Assembly, which is what the package is built on.
**FFmpeg.FS**
: Web Assembly always handles its memory, and in other to run FFmpeg
, we need to make it known to that file system by writing the file to the memory of the FFmpeg
. This is what this function does. It accepts the video as parameter and saves it in temporary memory.
N/B**:** It only stays in memory until the browser is refreshed
Next, is the FFmpeg.run()
function. We pass the following parameters:
**-i**
: is the input file**-t**
: is the time or length of the video**-ss**
: is the starting second**-f**
: is for encoding, in our case, gif**output.gif**
: is the name of the file we want to write to.
Once this is complete, it saves the file in memory;
Next, is to read the file by using the FFmpeg.Fs(readFile,``"
the file in memory``"``)
After that, we need to convert the file to a URL for our file-saver package to be able to make it downloadable. To do that we use the blob method.
1const url = URL.createObjectURL(2 new Blob([data.buffer], { type: 'image/gif' }),3);
And lastly, we pass the URL to the file-saver and specify the download name.
1saveAs(url, "output.gif");
Now we should have our A``pp.j``s
file like the one below.
1import { useEffect, useState } from "react"2import './App.css';3import { createFFmpeg, fetchFile } from "@ffmpeg/ffmpeg";4import { saveAs } from "file-saver";56const ffmpeg = createFFmpeg({ log: true });78function App() {9 const [video, setVideo] = useState();10 const [name, setName] = useState()11 const init = async () => {12 await ffmpeg.load();13 };1415 const setVid = (e) => {16 setVideo(e.target.files?.item(0))17 setName(e.target.files[0].name)18 }1920 const convertToGif = async () => {21 await ffmpeg.FS('writeFile', name, await fetchFile(video));22 await ffmpeg.run('-i', name, '-t', '2.5', '-ss', '2.0', '-f', 'gif', 'output.gif');23 const data = ffmpeg.FS('readFile', 'output.gif');24 const url = URL.createObjectURL(25 new Blob([data.buffer], { type: 'image/gif' }),26 );27 saveAs(url, "output.gif");28 };2930useEffect(() => {31 init();32}, []);3334return (35 <div className="App">36 <header className="App-header">37 {video && (38 <video controls width="250" src={URL.createObjectURL(video)}></video>39 )}40 <input type="file" onChange={(e) => setVid(e)} />41 <button onClick={convertToGif}>Download and Convert to GIF</button>42 </header>43 </div>44)45}46export default App;
Conclusion
In this tutorial, we implemented conversion of videos to GIFs with React, and ffmpeg.wasm
JavaScirpt wrappers @ffmpeg/ffmpeg
and @ffmpeg/core
.