<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
tsx
import {AbsoluteFill ,OffthreadVideo ,staticFile } from "remotion";export constMyVideo = () => {return (<AbsoluteFill ><OffthreadVideo src ={staticFile ("video.webm")} /></AbsoluteFill >);};
tsx
import {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:
tsx
export constMyComposition = () => {return (<AbsoluteFill ><OffthreadVideo src ="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" /></AbsoluteFill >);};
tsx
export 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.
transparent
optional, boolean
If set to true
, frames will be extracted as PNG, enabling transparency but also slowing down your render.
If set to false
(default), frames will be extracted as bitmap (BMP), which is faster.
imageFormat
imageFormat
removed in v4.0.0
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.
allowAmplificationDuringRender
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.tsxtsx
import {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.tsxtsx
import {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 >);};