Skip to main content

Playing videos in sequence

If you would like to play multiple videos in sequence, you can:

Define a component that renders a <Series> of <OffthreadVideo> components.
2
Create a calculateMetadata() function that fetches the duration of each video.
3
Register a <Composition> that specifies a list of videos.

Basic example

Start off by creating a component that renders a list of videos using the <Series> and <OffthreadVideo> component:

VideosInSequence.tsx
import React from 'react'; import {OffthreadVideo, Series} from 'remotion'; type VideoToEmbed = { src: string; durationInFrames: number | null; }; type Props = { videos: VideoToEmbed[]; }; export const VideosInSequence: React.FC<Props> = ({videos}) => { return ( <Series> {videos.map((vid) => { if (vid.durationInFrames === null) { throw new Error('Could not get video duration'); } return ( <Series.Sequence key={vid.src} durationInFrames={vid.durationInFrames}> <OffthreadVideo src={vid.src} /> </Series.Sequence> ); })} </Series> ); };

In the same file, create a function that calculates the metadata for the composition:

Calls parseMedia() to get the duration of each video.

Create a calculateMetadata() function that fetches the duration of each video.

Sums up all durations to get the total duration of the composition.

VideosInSequence.tsx
export const calculateMetadata: CalculateMetadataFunction<Props> = async ({props}) => { const fps = 30; const videos = await Promise.all([ ...props.videos.map(async (video): Promise<VideoToEmbed> => { const {slowDurationInSeconds} = await parseMedia({ src: video.src, fields: { slowDurationInSeconds: true, }, }); return { durationInFrames: Math.floor(slowDurationInSeconds * fps), src: video.src, }; }), ]); const totalDurationInFrames = videos.reduce((acc, video) => acc + (video.durationInFrames ?? 0), 0); return { props: { ...props, videos, }, fps, durationInFrames: totalDurationInFrames, }; };

In your root file, create a <Composition> that uses the VideosInSequence component and the exported calculateMetadata function:

Root.tsx
import React from 'react'; import {Composition, staticFile} from 'remotion'; import {VideosInSequence, calculateMetadata} from './VideosInSequence'; export const Root: React.FC = () => { return ( <Composition id="VideosInSequence" component={VideosInSequence} width={1920} height={1080} defaultProps={{ videos: [ { durationInFrames: null, src: 'https://remotion.media/BigBuckBunny.mp4', }, { durationInFrames: null, src: staticFile('localvideo.mp4'), }, ], }} calculateMetadata={calculateMetadata} /> ); };

Adding premounting

If you only care about the video looking smooth when rendered, you may skip this step.
If you also want smooth preview playback in the Player, consider this:

A video will only load when it is about to be played.
To create a smoother preview playback, we should do two things to all videos:

Add a premountFor prop to <Series.Sequence>. This will invisibly mount the video tag before it is played, giving it some time to load.

Add the pauseWhenBuffering prop. This will transition the Player into a buffering state, should the video still need to load.

VideosInSequence.tsx
export const VideosInSequence: React.FC<Props> = ({videos}) => { const {fps} = useVideoConfig(); return ( <Series> {videos.map((vid) => { if (vid.durationInFrames === null) { throw new Error('Could not get video duration'); } return ( <Series.Sequence key={vid.src} premountFor={4 * fps} durationInFrames={vid.durationInFrames}> <OffthreadVideo pauseWhenBuffering src={vid.src} /> </Series.Sequence> ); })} </Series> ); };

Browser autoplay policies

Mobile browsers are more aggressive in blocking autoplaying videos that enter after the start of the composition.

If you want to ensure a smooth playback experience for all videos, also read the notes about browser autoplay behavior and customize the behavior if needed.

See also