# Usage Learn the basics of using ffmpeg.wasm. :::note It is recommended to read [Overview](/docs/overview) first. ::: ## Transcode webm to mp4 video :::caution If you are a [vite](https://vitejs.dev/) user, use `esm` in **baseURL** instead of `umd`: ~~https://unpkg.com/@ffmpeg/core@0.12.5/dist/umd~~ => https://unpkg.com/@ffmpeg/core@0.12.5/dist/esm ::: ```jsx live // 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@0.12.5/dist/umd' const ffmpeg = ffmpegRef.current; ffmpeg.on('log', ({ message }) => { messageRef.current.innerHTML = message; console.log(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.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm')); await ffmpeg.exec(['-i', 'input.webm', 'output.mp4']); const data = await ffmpeg.readFile('output.mp4'); videoRef.current.src = URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'})); } return (loaded ? ( <>

Open Developer Tools (Ctrl+Shift+I) to View Logs

) : ( ) ); } ``` ## Transcode webm to mp4 video (multi-thread) :::caution As SharedArrayBuffer is required for multithread version, make sure you have have fulfilled [Security Requirements](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements). ::: ```jsx live // 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.5/dist/umd' const ffmpeg = ffmpegRef.current; ffmpeg.on('log', ({ message }) => { messageRef.current.innerHTML = message; console.log(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'), }); setLoaded(true); } const transcode = async () => { const ffmpeg = ffmpegRef.current; await ffmpeg.writeFile('input.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm')); await ffmpeg.exec(['-i', 'input.webm', 'output.mp4']); const data = await ffmpeg.readFile('output.mp4'); videoRef.current.src = URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'})); } return (loaded ? ( <>

Open Developer Tools (Ctrl+Shift+I) to View Logs

) : ( ) ); } ``` ## Transcode video with timeout ```jsx live // 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.5/dist/umd' const ffmpeg = ffmpegRef.current; ffmpeg.on('log', ({ message }) => { messageRef.current.innerHTML = message; console.log(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.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm')); // The exec should stop after 1 second. await ffmpeg.exec(['-i', 'input.webm', 'output.mp4'], 1000); const data = await ffmpeg.readFile('output.mp4'); videoRef.current.src = URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'})); } return (loaded ? ( <>

Open Developer Tools (Ctrl+Shift+I) to View Logs

) : ( ) ); } ``` ## Transcode video with progress (experimental) :::danger `progress` is an experimental feature and might not work for many cases (ex. concat video files, convert image files, ...). Please use with caution. ::: ```jsx live // 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.5/dist/umd' const ffmpeg = ffmpegRef.current; // Listen to progress event instead of log. ffmpeg.on('progress', ({ progress, time }) => { messageRef.current.innerHTML = `${progress * 100} % (transcoded time: ${time / 1000000} s)`; }); // 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.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm')); await ffmpeg.exec(['-i', 'input.webm', 'output.mp4']); const data = await ffmpeg.readFile('output.mp4'); videoRef.current.src = URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'})); } return (loaded ? ( <>

) : ( ) ); } ``` ## Split video into segments of equal duration ```jsx live // 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.5/dist/umd' const ffmpeg = ffmpegRef.current; ffmpeg.on('log', ({ message }) => { messageRef.current.innerHTML = message; console.log(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.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm')); await ffmpeg.exec([ '-i', 'input.webm', '-f', 'segment', '-segment_time', '3', '-g', '9', '-sc_threshold', '0', '-force_key_frames', 'expr:gte(t,n_forced*9)', '-reset_timestamps', '1', '-map', '0', 'output_%d.mp4' ]); const data = await ffmpeg.readFile('output_1.mp4'); videoRef.current.src = URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'})); } return (loaded ? ( <>

Open Developer Tools (Ctrl+Shift+I) to View Logs

) : ( ) ); } ``` ## Display Text on the video ```jsx live // 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.5/dist/umd' const ffmpeg = ffmpegRef.current; ffmpeg.on('log', ({ message }) => { messageRef.current.innerHTML = message; console.log(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.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm')); await ffmpeg.writeFile('arial.ttf', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/arial.ttf')); await ffmpeg.exec([ '-i', 'input.webm', '-vf', 'drawtext=fontfile=/arial.ttf:text=\'ffmpeg.wasm\':x=10:y=10:fontsize=24:fontcolor=white', 'output.mp4', ]); const data = await ffmpeg.readFile('output.mp4'); videoRef.current.src = URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'})); } return (loaded ? ( <>

Open Developer Tools (Ctrl+Shift+I) to View Logs

) : ( ) ); } ``` ## Interlace 2 Videos ```jsx live // 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.5/dist/umd' const ffmpeg = ffmpegRef.current; ffmpeg.on('log', ({ message }) => { messageRef.current.innerHTML = message; console.log(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.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s.webm')); await ffmpeg.writeFile('reversed.webm', await fetchFile('https://raw.githubusercontent.com/ffmpegwasm/testdata/master/Big_Buck_Bunny_180_10s_reversed.webm')); await ffmpeg.exec([ '-i', 'input.webm', '-i', 'reversed.webm', '-filter_complex', '[0:v][1:v]blend=all_expr=\'A*(if(eq(0,N/2),1,T))+B*(if(eq(0,N/2),T,1))\'', 'output.mp4', ]); const data = await ffmpeg.readFile('output.mp4'); videoRef.current.src = URL.createObjectURL(new Blob([data.buffer], {type: 'video/mp4'})); } return (loaded ? ( <>

Open Developer Tools (Ctrl+Shift+I) to View Logs

) : ( ) ); } ``` ## Use WORKERFS :::note Required: - @ffmpeg/ffmpeg@0.12.7+ - @ffmpeg/core@0.12.4+ ::: Please Check this PR: [Add WORKERFS support](https://github.com/ffmpegwasm/ffmpeg.wasm/pull/581) ## Abort exec() with signal :::note Required: - @ffmpeg/ffmpeg@0.12.7+ - @ffmpeg/core@0.12.4+ ::: Please check this PR: [abort signal](https://github.com/ffmpegwasm/ffmpeg.wasm/pull/573)