Video manipulation
You can draw frames of an <OffthreadVideo>
or a <Video>
onto a <canvas>
element using the drawImage()
API.
During preview, makes use of the requestVideoFrameCallback()
API.
Browser support: Firefox 130 (August 2024), Chrome 83, Safari 15.4.
Basic example
In this example, an <OffthreadVideo>
is rendered and made invisible.
Every frame that is emitted is drawn to a Canvas and a grayscale filter
is applied.
tsx
export constVideoOnCanvas :React .FC = () => {constvideo =useRef <HTMLVideoElement >(null);constcanvas =useRef <HTMLCanvasElement >(null);const {width ,height } =useVideoConfig ();// Process a frameconstonVideoFrame =useCallback ((frame :CanvasImageSource ) => {if (!canvas .current ) {return;}constcontext =canvas .current .getContext ('2d');if (!context ) {return;}context .filter = 'grayscale(100%)';context .drawImage (frame , 0, 0,width ,height );},[height ,width ],);return (<AbsoluteFill ><AbsoluteFill ><OffthreadVideo // Hide the original video tagstyle ={{opacity : 0}}onVideoFrame ={onVideoFrame }src ="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"/></AbsoluteFill ><AbsoluteFill ><canvas ref ={canvas }width ={width }height ={height } /></AbsoluteFill ></AbsoluteFill >);};
tsx
export constVideoOnCanvas :React .FC = () => {constvideo =useRef <HTMLVideoElement >(null);constcanvas =useRef <HTMLCanvasElement >(null);const {width ,height } =useVideoConfig ();// Process a frameconstonVideoFrame =useCallback ((frame :CanvasImageSource ) => {if (!canvas .current ) {return;}constcontext =canvas .current .getContext ('2d');if (!context ) {return;}context .filter = 'grayscale(100%)';context .drawImage (frame , 0, 0,width ,height );},[height ,width ],);return (<AbsoluteFill ><AbsoluteFill ><OffthreadVideo // Hide the original video tagstyle ={{opacity : 0}}onVideoFrame ={onVideoFrame }src ="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"/></AbsoluteFill ><AbsoluteFill ><canvas ref ={canvas }width ={width }height ={height } /></AbsoluteFill ></AbsoluteFill >);};
Greenscreen example
In this example, we loop over each pixel in the image buffer and if it's green, we transparentize it. Drag the slider below to turn the video transparent.
tsx
export constGreenscreen :React .FC <{opacity : number;}> = ({opacity }) => {constcanvas =useRef <HTMLCanvasElement >(null);const {width ,height } =useVideoConfig ();// Process a frameconstonVideoFrame =useCallback ((frame :CanvasImageSource ) => {if (!canvas .current ) {return;}constcontext =canvas .current .getContext ('2d');if (!context ) {return;}context .drawImage (frame , 0, 0,width ,height );constimageFrame =context .getImageData (0, 0,width ,height );const {length } =imageFrame .data ;// If the pixel is very green, reduce the alpha channelfor (leti = 0;i <length ;i += 4) {constred =imageFrame .data [i + 0];constgreen =imageFrame .data [i + 1];constblue =imageFrame .data [i + 2];if (green > 100 &&red < 100 &&blue < 100) {imageFrame .data [i + 3] =opacity * 255;}}context .putImageData (imageFrame , 0, 0);},[height ,width ],);return (<AbsoluteFill ><AbsoluteFill ><OffthreadVideo style ={{opacity : 0}}onVideoFrame ={onVideoFrame }src ="https://remotion-assets.s3.eu-central-1.amazonaws.com/just-do-it-short.mp4"/></AbsoluteFill ><AbsoluteFill ><canvas ref ={canvas }width ={width }height ={height } /></AbsoluteFill ></AbsoluteFill >);};
tsx
export constGreenscreen :React .FC <{opacity : number;}> = ({opacity }) => {constcanvas =useRef <HTMLCanvasElement >(null);const {width ,height } =useVideoConfig ();// Process a frameconstonVideoFrame =useCallback ((frame :CanvasImageSource ) => {if (!canvas .current ) {return;}constcontext =canvas .current .getContext ('2d');if (!context ) {return;}context .drawImage (frame , 0, 0,width ,height );constimageFrame =context .getImageData (0, 0,width ,height );const {length } =imageFrame .data ;// If the pixel is very green, reduce the alpha channelfor (leti = 0;i <length ;i += 4) {constred =imageFrame .data [i + 0];constgreen =imageFrame .data [i + 1];constblue =imageFrame .data [i + 2];if (green > 100 &&red < 100 &&blue < 100) {imageFrame .data [i + 3] =opacity * 255;}}context .putImageData (imageFrame , 0, 0);},[height ,width ],);return (<AbsoluteFill ><AbsoluteFill ><OffthreadVideo style ={{opacity : 0}}onVideoFrame ={onVideoFrame }src ="https://remotion-assets.s3.eu-central-1.amazonaws.com/just-do-it-short.mp4"/></AbsoluteFill ><AbsoluteFill ><canvas ref ={canvas }width ={width }height ={height } /></AbsoluteFill ></AbsoluteFill >);};
Before v4.0.190
Before v4.0.190, the onVideoFrame
prop of <OffthreadVideo>
and <Video>
was not supported.
You could only manipulate a <Video>
using the requestVideoFrameCallback
API.
Click here to see the old version of this page.