Refactor frontend thumbnail handling
This commit is contained in:
parent
7eef0b6e25
commit
8a69a07cc7
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue