如何在react-konva中捕获视频的第一帧

问题描述 投票:0回答:2

我使用react-konva制作了一个简单的视频播放器,我想在播放视频之前将第一帧显示为缩略图。

这是我的方法:

我使用 Konva.Image 来显示视频,并使用 Konva.Animation 来更新图像。

import Konva from "konva";
import React, { useState, useRef, useEffect } from "react";
import { Stage, Layer, Image, Text } from "react-konva";

function VideoPlayer({ width, height }) {
  const video = useRef();
  const image = useRef();
  const anim = useRef();
  const text = useRef();
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    anim.current = new Konva.Animation(() => {
      image.current.image(video.current);
    }, image.current.getLayer());
  });

  return (
    <div>
      <button
        onClick={() => {
          text.current.destroy();
          video.current.play();
          anim.current.start();
        }}
      >
        PLAY
      </button>
      <button
        onClick={() => {
          video.current.pause();
          anim.current.stop();
        }}
      >
        PAUSE
      </button>
      <video
        style={{ display: "none" }}
        ref={video}
        onLoadedData={() => {
          setLoading(false);
        }}
        src="https://upload.wikimedia.org/wikipedia/commons/transcoded/c/c4/Physicsworks.ogv/Physicsworks.ogv.240p.vp9.webm"
      />
      <Stage width={window.innerWidth} height={window.innerHeight}>
        <Layer>
          <Text
            ref={text}
            text={loading ? "Loading..." : "Press PLAY..."}
            {...{
              width: window.innerWidth,
              height: window.innerHeight,
              align: "center",
              verticalAlign: "middle"
            }}
          />
          <Image
            x={100}
            y={100}
            ref={image}
            width={width}
            height={height}
            stroke="black"
          />
        </Layer>
      </Stage>
    </div>
  );
}

export default VideoPlayer;

我在这里创建了我的实现的工作演示

reactjs html5-canvas html5-video konvajs react-konva
2个回答
4
投票

您可以使用钩子来:

  1. 为预览图像创建画布元素
  2. 创建视频元素
  3. 等待视频加载
  4. 将第一帧绘制到画布中
  5. 当视频未播放时,使用预览画布作为源
const usePreview = (url) => {
  const [canvas, setCanvas] = useState(null);

  useEffect(() => {
    const video = document.createElement("video");
    video.src = url;
    const onLoad = () => {
      const canvas = document.createElement("canvas");
      canvas.width = video.videoWidth;
      canvas.height = video.videoHeight;
      video.currentTime = 1;
      const ctx = canvas.getContext("2d");
      ctx.drawImage(video, 0, 0);
      setCanvas(canvas);
    };
    video.addEventListener("canplay", onLoad);
    return () => video.removeEventListener("load", onLoad);
  }, [url]);

  return canvas;
};

完整演示:https://codesandbox.io/s/react-konva-video-preview-0we9d?file=/src/index.js


0
投票

也许这对某人有用。如果自定义钩子

usePreview()
不断调用,我们需要将 eventListener
canplay
更改为
loadedmetadata
seeked
。解决办法如下:

返回画布:

const usePreview = (url) => {
  const [canvas, setCanvas] = useState(null);

  useEffect(() => {
    const video = document.createElement("video");
    video.src = url;
    video.crossOrigin = "anonymous";

    const onSeeked = () => {
      const newCanvas = document.createElement("canvas");
      newCanvas.width = video.videoWidth;
      newCanvas.height = video.videoHeight;
      const ctx = newCanvas.getContext("2d");
      ctx.drawImage(video, 0, 0);
      setCanvas(newCanvas);
    };

    video.addEventListener("seeked", onSeeked);

    const onLoadMetadata = () => video.currentTime = 0;

    video.addEventListener("loadedmetadata", onLoadMetadata);

    return () => {
      video.removeEventListener("seeked", onSeeked);
      video.removeEventListener("loadedmetadata", onLoadMetadata);
      video.pause();
      video.src = "";
    };
  }, [url]);

  return canvas;
};

返回图片网址:

const usePreview = (url) => {
  const [imageUrl, setImageUrl] = useState(null);

  useEffect(() => {
    const video = document.createElement("video");
    video.src = url;
    video.crossOrigin = "anonymous";

    const onSeeked = () => {
      const newCanvas = document.createElement("canvas");
      newCanvas.width = video.videoWidth;
      newCanvas.height = video.videoHeight;
      const ctx = newCanvas.getContext("2d");
      ctx.drawImage(video, 0, 0);
      const CanvasToURL = newCanvas.toDataURL()
      setImageUrl(CanvasToURL);
    };

    video.addEventListener("seeked", onSeeked);

    const onLoadMetadata = () => video.currentTime = 0;

    video.addEventListener("loadedmetadata", onLoadMetadata);

    return () => {
      video.removeEventListener("seeked", onSeeked);
      video.removeEventListener("loadedmetadata", onLoadMetadata);
      video.pause();
      video.src = "";
    };
  }, [url]);

  return imageUrl;
};
© www.soinside.com 2019 - 2024. All rights reserved.