<OffthreadVideo>
Available from Remotion 3.0.11
This component imports and displays a video, similar to <Video/>, but during rendering, extracts the exact frame from the video and displays it in a <Img> tag. This extraction process happens outside the browser using FFMPEG.
This component was designed to combat limitations of the default <Video> element. See: <Video> vs <OffthreadVideo>.
Example
tsximport {AbsoluteFill ,OffthreadVideo ,staticFile } from "remotion";export constMyVideo = () => {return (<AbsoluteFill ><OffthreadVideo src ={staticFile ("video.webm")} /></AbsoluteFill >);};
tsximport {AbsoluteFill ,OffthreadVideo ,staticFile } from "remotion";export constMyVideo = () => {return (<AbsoluteFill ><OffthreadVideo src ={staticFile ("video.webm")} /></AbsoluteFill >);};
You can load a video from an URL as well:
tsxexport constMyComposition = () => {return (<AbsoluteFill ><OffthreadVideo src ="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" /></AbsoluteFill >);};
tsxexport constMyComposition = () => {return (<AbsoluteFill ><OffthreadVideo src ="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" /></AbsoluteFill >);};
Props
The props volume, playbackRate, muted and acceptableTimeShiftInSeconds are supported and work the same as in <Video>.
The props onError, className and style are supported and get passed to the underlying HTML element. Remember that during render, this is a <img> element, and during preview, this is a <video> element.
imageFormatv3.0.22
Either jpeg or png. Default jpeg.
With png, transparent videos (VP8, VP9, ProRes) can be displayed, however it is around 40% slower, with VP8 videos being much slower.
allowAmplificationDuringRenderv3.3.17
Make values for volume greater than 1 result in amplification during renders.
During Preview, the volume will be limited to 1, since the browser cannot amplify audio.
onError
Handle an error playing the video. From v3.3.89, if you pass an onError callback, then no exception will be thrown. Previously, the error could not be caught.
Performance tips
Avoid embedding a video beyond it's end (for example: Rendering a 5 second video inside 10 second composition). To create parity with the <Video> element, the video still displays its last frame in that case. However, to fetch the last frame specifically is a significantly more expensive operation than a frame from a known timestamp.
Looping a video
Unlike <Video>, OffthreadVideo does not currently implement the loop property. You can use the following snippet that uses @remotion/media-utils to loop a video.
LoopedOffthreadVideo.tsxtsximport {getVideoMetadata } from "@remotion/media-utils";importReact , {useEffect ,useState } from "react";import {cancelRender ,continueRender ,delayRender ,Loop ,OffthreadVideo ,staticFile ,useVideoConfig ,} from "remotion";constsrc =staticFile ("myvideo.mp4");export constLoopedOffthreadVideo :React .FC = () => {const [duration ,setDuration ] =useState <null | number>(null);const [handle ] =useState (() =>delayRender ());const {fps } =useVideoConfig ();useEffect (() => {getVideoMetadata (src ).then (({durationInSeconds }) => {setDuration (durationInSeconds );continueRender (handle );}).catch ((err ) => {cancelRender (handle );console .log (err );});}, [handle ]);if (duration === null) {return null;}return (<Loop durationInFrames ={Math .floor (fps *duration )}><OffthreadVideo src ={src } /></Loop >);};
LoopedOffthreadVideo.tsxtsximport {getVideoMetadata } from "@remotion/media-utils";importReact , {useEffect ,useState } from "react";import {cancelRender ,continueRender ,delayRender ,Loop ,OffthreadVideo ,staticFile ,useVideoConfig ,} from "remotion";constsrc =staticFile ("myvideo.mp4");export constLoopedOffthreadVideo :React .FC = () => {const [duration ,setDuration ] =useState <null | number>(null);const [handle ] =useState (() =>delayRender ());const {fps } =useVideoConfig ();useEffect (() => {getVideoMetadata (src ).then (({durationInSeconds }) => {setDuration (durationInSeconds );continueRender (handle );}).catch ((err ) => {cancelRender (handle );console .log (err );});}, [handle ]);if (duration === null) {return null;}return (<Loop durationInFrames ={Math .floor (fps *duration )}><OffthreadVideo src ={src } /></Loop >);};