Skip to main content

Handling user video uploads

In an app where users can upload videos and edit them, we can create a better user experience by loading the video into a player even before the upload is finished. Good news: This can be done pretty easily!

Allowing user uploads

We have a component which returns a <OffthreadVideo> tag that includes an URL as source.

MyComposition.tsx
tsx
import {AbsoluteFill, OffthreadVideo} from'remotion';
typeVideoProps= {
videoURL:string;
};
exportconstMyComponent:React.FC<VideoProps> = ({videoURL}) => {
return (
<AbsoluteFill>
<OffthreadVideosrc={videoURL} />
</AbsoluteFill>
);
};

The video URL will be passed from the Remotion Player to our component.
Using a <input type="file"> element, we allow a user upload.
As soon as a file is fully uploaded to the cloud, the URL will be set and can be used by the component to display the video.

App.tsx
tsx
import {Player} from'@remotion/player';
import {useState} from'react';
exportconstRemotionPlayer:React.FC= () => {
const [videoUrl, setVideoUrl] =useState<string|null>(null);
consthandleChange=useCallback(async (event:React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files ===null) {
return;
}
constfile= event.target.files[0];
//upload is an example function & returns a URL when a file is uploaded on the cloud.
constcloudURL=awaitupload(file);
// E.g., cloudURL = https://exampleBucketName.s3.ExampleAwsRegion.amazonaws.com
setVideoUrl(cloudURL);
}, []);
return (
<div>
{videoUrl ===null?null: <Playercomponent={MyComposition} durationInFrames={120} compositionWidth={1920} compositionHeight={1080} fps={30} inputProps={{videoUrl}} />}
<inputtype="file"onChange={handleChange} />
</div>
);
};

The implementation of the upload() function is provider-specific and we do not show an implementation in this article. We assume it is a function that takes a file, uploads it and returns an URL.

Optimistic updates

When we start the upload of the file, we can create a blob URL using URL.createObjectURL() which can be used to display the local file in a <Video> tag. When the file is done uploading and we get the remote URL, the component shall use remote URL as source.

App.tsx
tsx
import {Player} from'@remotion/player';
import {useCallback, useState} from'react';
typeVideoState=
| {
type:'empty';
}
| {
type:'blob'|'cloud';
url:string;
};
exportconstRemotionPlayer:React.FC= () => {
const [videoState, setVideoState] =useState<VideoState>({
type: 'empty',
});
consthandleChange=useCallback(async (event:React.ChangeEvent<HTMLInputElement>) => {
if (event.target.files ===null) {
return;
}
constfile= event.target.files[0];
constblobUrl=URL.createObjectURL(file);
setVideoState({type: 'blob', url: blobUrl});
constcloudUrl=awaitupload(file);
setVideoState({type: 'cloud', url: cloudUrl});
URL.revokeObjectURL(blobUrl);
}, []);
return (
<div>
{videoState.type !=='empty'? <Playercomponent={MyComposition} durationInFrames={120} compositionWidth={1920} compositionHeight={1080} fps={30} inputProps={{videoUrl: videoState.url}} /> :null}
<inputtype="file"onChange={handleChange} />
</div>
);
};

This will result in the user immediately seeing the video as they drag it into the input field. It is a good practice to call URL.revokeObjectURL() after the local video is not used anymore to free up the used memory.

note

As soon as possible, replace the blob: URL with the real URL.
Since blob: URLs don't support the HTTP Range header, video seeking performance is degraded when using blob: URLs.

Validating video compatibility

Before uploading a video, you should validate whether the browser can decode it. This saves bandwidth and provides immediate feedback to the user. For a complete guide on validating user videos including handling incompatible formats, see Validating user videos.

See also

AltStyle によって変換されたページ (->オリジナル) /