Usage
Learn the basics of using ffmpeg.wasm.
note
It is recommended to read Overview first.
Transcoding video
tip
Load ffmpeg-core
might take a few minutes to complete as it downloads
a ~31 MB ffmpeg-core.wasm.
Live Editor
// import { FFmpeg } from '@ffmpeg/ffmpeg';// import { fetchFile } from '@ffmpeg/util';function() {const [loaded, setLoaded] = useState(false);const ffmpegRef = useRef(new FFmpeg());const videoRef = useRef(null);const messageRef = useRef(null);const load = async () => {const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd'const ffmpeg = ffmpegRef.current;ffmpeg.on("log", ({ message }) => {messageRef.current.innerHTML = message;});// toBlobURL is used to bypass CORS issue, urls with the same// domain can be used directly.await ffmpeg.load({coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`,"text/javascript",),wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`,"application/wasm",),});setLoaded(true);}const transcode = async () => {const ffmpeg = ffmpegRef.current;await ffmpeg.writeFile("input.avi",await fetchFile('/video/video-15s.avi'));await ffmpeg.exec(['-i', 'input.avi', 'output.mp4']);const data = await ffmpeg.readFile('output.mp4');videoRef.current.src =URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));}return (loaded? (<><video ref={videoRef} controls></video><br/><button onClick={transcode}>Transcode avi to mp4</button><p ref={messageRef}></p></>): (<button onClick={load}>Load ffmpeg-core</button>));}
Result
Loading...
Transcoding video (multi-thread)
tip
Load ffmpeg-core
might take a few minutes to complete as it downloads
a ~31 MB ffmpeg-core.wasm.
Live Editor
// import { FFmpeg } from '@ffmpeg/ffmpeg';// import { fetchFile, toBlobURL } from '@ffmpeg/util';function() {const [loaded, setLoaded] = useState(false);const ffmpegRef = useRef(new FFmpeg());const videoRef = useRef(null);const messageRef = useRef(null);const load = async () => {const baseURL = 'https://unpkg.com/@ffmpeg/core-mt@0.12.2/dist/umd'const ffmpeg = ffmpegRef.current;ffmpeg.on("log", ({ message }) => {messageRef.current.innerHTML = message;});// toBlobURL is used to bypass CORS issue, urls with the same// domain can be used directly.await ffmpeg.load({coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`,"text/javascript",),wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`,"application/wasm",),workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`,"text/javascript",),thread: true,});setLoaded(true);}const transcode = async () => {const ffmpeg = ffmpegRef.current;await ffmpeg.writeFile("input.avi",await fetchFile('/video/video-15s.avi'));await ffmpeg.exec(['-i', 'input.avi', 'output.mp4']);const data = await ffmpeg.readFile('output.mp4');videoRef.current.src =URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));}return (loaded? (<><video ref={videoRef} controls></video><br/><button onClick={transcode}>Transcode avi to mp4</button><p ref={messageRef}></p></>): (<button onClick={load}>Load ffmpeg-core</button>));}
Result
Loading...
caution
As SharedArrayBuffer is required for multithread version, make sure you have have fulfilled Security Requirements.
Transcoding video with timeout
Live Editor
// import { FFmpeg } from '@ffmpeg/ffmpeg';// import { fetchFile } from '@ffmpeg/util';function() {const [loaded, setLoaded] = useState(false);const ffmpegRef = useRef(new FFmpeg());const videoRef = useRef(null);const messageRef = useRef(null);const load = async () => {const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd'const ffmpeg = ffmpegRef.current;ffmpeg.on("log", ({ message }) => {messageRef.current.innerHTML = message;});// toBlobURL is used to bypass CORS issue, urls with the same// domain can be used directly.await ffmpeg.load({coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`,"text/javascript",),wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`,"application/wasm",),});setLoaded(true);}const transcode = async () => {const ffmpeg = ffmpegRef.current;await ffmpeg.writeFile("input.avi",await fetchFile('/video/video-15s.avi'));// The exec should stop after 1 second.await ffmpeg.exec(['-i', 'input.avi', 'output.mp4'], 1000);const data = await ffmpeg.readFile('output.mp4');videoRef.current.src =URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));}return (loaded? (<><video ref={videoRef} controls></video><br/><button onClick={transcode}>Transcode avi to mp4</button><p ref={messageRef}></p></>): (<button onClick={load}>Load ffmpeg-core</button>));}
Result
Loading...
Transcoding video with progress
Live Editor
// import { FFmpeg } from '@ffmpeg/ffmpeg';// import { fetchFile } from '@ffmpeg/util';function() {const [loaded, setLoaded] = useState(false);const ffmpegRef = useRef(new FFmpeg());const videoRef = useRef(null);const messageRef = useRef(null);const load = async () => {const baseURL = 'https://unpkg.com/@ffmpeg/core@0.12.2/dist/umd'const ffmpeg = ffmpegRef.current;// Listen to progress event instead of log.ffmpeg.on("progress", ({ progress }) => {messageRef.current.innerHTML = `${progress * 100} %`;});// toBlobURL is used to bypass CORS issue, urls with the same// domain can be used directly.await ffmpeg.load({coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`,"text/javascript",),wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`,"application/wasm",),});setLoaded(true);}const transcode = async () => {const ffmpeg = ffmpegRef.current;await ffmpeg.writeFile("input.avi",await fetchFile('/video/video-15s.avi'));await ffmpeg.exec(['-i', 'input.avi', 'output.mp4']);const data = await ffmpeg.readFile('output.mp4');videoRef.current.src =URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'}));}return (loaded? (<><video ref={videoRef} controls></video><br/><button onClick={transcode}>Transcode avi to mp4</button><p ref={messageRef}></p></>): (<button onClick={load}>Load ffmpeg-core</button>));}
Result
Loading...
caution
progress
is an experimental feature and might not work for many cases
(ex. concat video files, convert image files, ...). Please use with caution.