Refactor frontend thumbnail handling

This commit is contained in:
Rob Watson 2021-11-22 19:20:40 +01:00
parent 7eef0b6e25
commit 8a69a07cc7
1 changed files with 42 additions and 66 deletions

View File

@ -21,82 +21,58 @@ export const VideoPreview: React.FC<Props> = ({
// effects // effects
// load thumbnail, to display when the component is loaded for the first
// time. This is needed because of browser autoplay limitations.
useEffect(() => {
(async function () {
if (mediaSet == null) {
return;
}
const canvas = videoCanvasRef.current;
if (canvas == null) {
console.error('no canvas ref available');
return;
}
const ctx = canvas.getContext('2d');
if (ctx == null) {
console.error('no 2d context available');
return;
}
// Set aspect ratio.
canvas.width = canvas.height * (canvas.clientWidth / canvas.clientHeight);
console.log('getting video thumbnail...');
const rpc = newRPC();
const service = new MediaSetServiceClientImpl(rpc);
const thumbnail = await service.GetVideoThumbnail({ id: mediaSet.id });
console.log('got thumbnail', thumbnail);
const url = URL.createObjectURL(
new Blob([thumbnail.image], { type: 'image/jpeg' })
);
const img = new Image(thumbnail.width, thumbnail.height);
img.src = url;
console.log('img', img);
img.onerror = console.error;
img.onload = () => {
ctx.drawImage(img, 0, 0, 177, 100);
};
console.log('set src to', url);
})();
}, [mediaSet]);
// render canvas // render canvas
useEffect(() => { useEffect(() => {
// TODO: not sure if requestAnimationFrame is recommended here. // TODO: not sure if requestAnimationFrame is recommended here.
requestAnimationFrame(() => { requestAnimationFrame(() => {
const canvas = videoCanvasRef.current; (async function () {
if (canvas == null) { const canvas = videoCanvasRef.current;
console.error('no canvas ref available'); if (canvas == null) {
return; console.error('no canvas ref available');
} return;
}
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
if (ctx == null) { if (ctx == null) {
console.error('no 2d context available'); console.error('no 2d context available');
return; return;
} }
// Set aspect ratio. // Set aspect ratio.
canvas.width = canvas.height * (canvas.clientWidth / canvas.clientHeight); canvas.width =
canvas.height * (canvas.clientWidth / canvas.clientHeight);
const durSecs = duration / 1000; // If the required position is 0, display the thumbnail instead of
const ratio = position / durSecs; // trying to render the video. The most important use case is before a
const x = (canvas.width - 177) * ratio; // click event has happened, when autoplay restrictions will prevent
// the video being rendered to canvas.
if (position == 0) {
const service = new MediaSetServiceClientImpl(newRPC());
const thumbnail = await service.GetVideoThumbnail({
id: mediaSet.id,
});
ctx.clearRect(0, 0, x, canvas.height); // TODO: avoid fetching the image every re-render:
ctx.clearRect(x + 177, 0, canvas.width - 177 - x, canvas.height); const url = URL.createObjectURL(
new Blob([thumbnail.image], { type: 'image/jpeg' })
);
const img = new Image(thumbnail.width, thumbnail.height);
ctx.drawImage(video, x, 0, 177, 100); img.src = url;
img.onload = () => ctx.drawImage(img, 0, 0, 177, 100);
return;
}
// otherwise, render the video, which (should) work now.
const durSecs = duration / 1000;
const ratio = position / durSecs;
const x = (canvas.width - 177) * ratio;
ctx.clearRect(0, 0, x, canvas.height);
ctx.clearRect(x + 177, 0, canvas.width - 177 - x, canvas.height);
ctx.drawImage(video, x, 0, 177, 100);
})();
}); });
}, [position]); }, [mediaSet, position]);
// render component // render component