【React】videoフレームをキャプチャして表示する

こんにちは、フリーランスエンジニアの太田雅昭です。

videoフレームのキャプチャ

videoフレームは、canvasを使用してキャプチャできます。以下のような具合です。

import { useRef } from "react";

export default function App() {
    const videoRef = useRef<HTMLVideoElement>(null);
    const canvasRef = useRef<HTMLCanvasElement>(null);

    function captureFrame() {
        const video = videoRef.current;
        const canvas = canvasRef.current;

        if (!video || !canvas) {
            throw new Error('video or canvas is null');
        }

        const context = canvas.getContext("2d");
        if (!context) {
            throw new Error('context is null');
        }

        context.drawImage(video, 0, 0, canvas.width, canvas.height);
    }

    return <>
        <button onClick={captureFrame}>キャプチャ</button>

        <video
            ref={videoRef}
            controls
            src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
        />

        <canvas ref={canvasRef} />
    </>
};

リアルタイムで描画する

リアルタイムで描画するには、requestAnimationFrameを用います。以下のような具合です。

const drawFrame = () => {
    const video = videoRef.current;
    const canvas = canvasRef.current;

    if (!video || !canvas) {
        throw new Error('video or canvas is null');
    }

    const context = canvas.getContext("2d");
    if (!context) {
        throw new Error('context is null');
    }

    // Canvasに現在の動画フレームを描画
    context.drawImage(video, 0, 0, canvas.width, canvas.height);

    // 次のフレームをリクエストして、アニメーションを続ける
    requestAnimationFrame(drawFrame);
}

再利用はCORSに注意

canvasをtoDataURLでimg srcに入れようとすると、CORSエラーになります。またtoBlobも使えないそうです(ChatGPT大先生言)。自サーバーの動画のみなら問題ありませんが、他サーバーの動画も扱う可能性がある場合は、canvasをそのまま使用するのがよさそうです。