Update thumbnail generation example to use cursors

This commit is contained in:
Vanilagy
2025-12-21 10:50:32 +01:00
parent 3fa95cb449
commit ece27cca79
3 changed files with 20 additions and 9 deletions
@@ -1,6 +1,7 @@
import { Input, ALL_FORMATS, BlobSource, UrlSource, CanvasSink } from 'mediabunny';
import { Input, ALL_FORMATS, BlobSource, UrlSource, VideoSampleCursor } from 'mediabunny';
import SampleFileUrl from '../../docs/assets/big-buck-bunny-trimmed.mp4';
import { canvasTransformer } from '../../src/cursors.js';
(document.querySelector('#sample-file-download') as HTMLAnchorElement).href = SampleFileUrl;
const selectMediaButton = document.querySelector('#select-file') as HTMLButtonElement;
@@ -69,16 +70,23 @@ const generateThumbnails = async (resource: File | string) => {
(_, i) => firstTimestamp + i * (lastTimestamp - firstTimestamp) / THUMBNAIL_COUNT,
);
// Create a CanvasSink for extracting resized frames from the video track
const sink = new CanvasSink(videoTrack, {
width: Math.floor(width * window.devicePixelRatio),
height: Math.floor(height * window.devicePixelRatio),
fit: 'fill',
// Create a cursor to extract frames from the video
const cursor = new VideoSampleCursor(videoTrack, {
transform: canvasTransformer({
width: Math.floor(width * window.devicePixelRatio),
height: Math.floor(height * window.devicePixelRatio),
fit: 'fill',
}),
});
// Queue all cursor commands at once, including closing the cursor; this allows it to optimize access patterns
const promises = timestamps.map(x => cursor.seekTo(x));
void cursor.close();
// Iterate over all thumbnail canvases
let i = 0;
for await (const wrappedCanvas of sink.canvasesAtTimestamps(timestamps)) {
for (const promise of promises) {
const wrappedCanvas = await promise;
const container = thumbnailElements[i]!;
if (wrappedCanvas) {
+1 -1
View File
@@ -930,7 +930,6 @@ export abstract class SampleCursor<
this._lastPendingRequest = pendingRequest;
this._pumpGate.open();
deferred.execute(); // Waiting for the return would be too long
return res.set(await request.promise);
@@ -987,6 +986,7 @@ export abstract class SampleCursor<
}
this._lastPendingRequest = pendingRequest;
this._pumpGate.open();
lock.release(); // Waiting for the return would be too long
return res.set(await request.promise);
+4 -1
View File
@@ -2368,7 +2368,10 @@ abstract class IsobmffTrackBacking implements InputTrackBacking {
}
async getFirstTimestamp() {
const firstPacket = await this.getFirstPacket({ metadataOnly: true });
const result = new ResultValue<EncodedPacket | null>();
await this.getFirstPacket(result, { metadataOnly: true });
const firstPacket = result.value;
return firstPacket?.timestamp ?? 0;
}