Extracting a thumbnail from a video in JavaScript
Extracting a single frame (thumbnail) from a video file can be done using Mediabunny.
Here's an extractThumbnail() function you can copy and paste into your project:
extract-thumbnail.tstsimport {ALL_FORMATS ,Input ,InputDisposedError ,UrlSource ,VideoSample ,VideoSampleSink } from'mediabunny';exporttypeExtractThumbnailProps = {src :string;timestampInSeconds :number;signal ?:AbortSignal ;};exportasyncfunctionextractThumbnail ({src ,timestampInSeconds ,signal }:ExtractThumbnailProps ):Promise <VideoSample > {usinginput =newInput ({formats :ALL_FORMATS ,source : newUrlSource (src ),});constvideoTrack =awaitinput .getPrimaryVideoTrack ();if (!videoTrack ) {thrownewError ('No video track found in the input');}if (signal ?.aborted ) {thrownewError ('Aborted');}constsink =newVideoSampleSink (videoTrack );constsample =awaitsink .getSample (timestampInSeconds );if (!sample ) {thrownewError (`No frame found at timestamp ${timestampInSeconds }s`);}returnsample ;}
Example
Here is how you can draw a thumbnail to a canvas:
tsxconstsample =awaitextractThumbnail ({src : 'https://remotion.media/video.mp4',timestampInSeconds : 5,});constcanvas =document .createElement ('canvas');canvas .width =sample .displayWidth ;canvas .height =sample .displayHeight ;constctx =canvas .getContext ('2d');sample .draw (ctx !, 0, 0);sample .close ();
Memory management
The function returns a VideoSample object. When it gets cleaned up by garbage collection, it will be automatically closed, but a warning will be printed.
You can call .close() to explicitly close the sample and prevent the warning from being printed.
Explicitly closing a sampletsconstsample=awaitextractThumbnail({src: 'https://example.com/video.mp4',timestampInSeconds: 5,});sample.draw(ctx!, 0, 0);sample.close();
Or, you can use the using statement to clean up the sample when it goes out of scope.
tsusing sample =awaitextractThumbnail({src: 'https://example.com/video.mp4',timestampInSeconds: 5,});sample.draw(ctx!, 0, 0);
Abort frame extraction
Pass an AbortSignal to cancel thumbnail extraction:
tsconstcontroller =newAbortController ();setTimeout (() =>controller .abort (), 5000);try {usingsample =awaitextractThumbnail ({src : 'https://example.com/video.mp4',timestampInSeconds : 10,signal :controller .signal ,});console .log ('Got frame!');} catch (error ) {console .error ('Thumbnail extraction was aborted or failed:',error );}
Setting a timeout
Here is how you can set a maximum duration for extracting a thumbnail:
Fail if not able to extract within 5 secondstsconstcontroller =newAbortController ();consttimeoutPromise =newPromise <never>((_ ,reject ) => {consttimeoutId =setTimeout (() => {controller .abort ();reject (newError ('Thumbnail extraction timed out after 5 seconds'));}, 5000);controller .signal .addEventListener ('abort', () =>clearTimeout (timeoutId ), {once : true});});try {usingsample =awaitPromise .race ([extractThumbnail ({src : 'https://example.com/video.mp4',timestampInSeconds : 10,signal :controller .signal ,}),timeoutPromise ,]);console .log ('Got frame!');} catch (error ) {console .error ('Thumbnail extraction was aborted or failed:',error );}
See also
- Extracting video frames - Extract multiple frames from a video
- Mediabunny Documentation
- Packets & samples in Mediabunny
VideoSampleSinkAPI- Supported formats