Вызов load на теге видео перед переходом на холст прерывает его в React - PullRequest
0 голосов
/ 09 мая 2020

У меня есть функциональный компонент React, в котором я загружаю видео и пытаюсь передать его объекту холста.

Соответствующая часть кода:

function onUploadVideoChange(event) {
event.persist();

const file = event.target.files[0];
const isAllowed = file.type === 'video/mp4';

if (!isAllowed) {
  alert('Only mp4 videos are allowed');
}
else {
  setUrlSource(URL.createObjectURL(file));
  videoRef.current.setAttribute('src', urlSource);
  videoRef.current.load();
  videoRef.current.addEventListener('loadedmetadata', () => {
    const videoLength = videoRef.current.duration;
    const videoWidth = videoRef.current.videoWidth;
    const videoHeight = videoRef.current.videoHeight;

    const ctx = canvasRef.current.getContext('2d');
    canvasRef.current.width = videoWidth;
    canvasRef.current.height = videoHeight;

    ctx.drawImage(videoRef.current, 0, 0, videoWidth, videoHeight);
  });
}

И внизу на моем рендере находится эта часть:

    <video ref={videoRef} controls>
      <source type="video/mp4" ref={sourceRef} src={urlSource} />
    </video>
    <canvas ref={canvasRef}></canvas>

Как видите, я использую хуки useRef, но видео не загружается на холст.

После некоторого покопания , Я выяснил, что это звонок .load(), который по какой-то причине его нарушает. Если я жестко закодирую URL-адрес видео на <source>, он будет работать нормально.

Вот ручка с ним:

https://codepen.io/souljacker/pen/abvGmpy?editors=1011

I Я регистрирую videoRef после вызова load (), и видео уже есть с правильным sr c. Так что я застрял.

Есть помощь?

1 Ответ

0 голосов
/ 10 мая 2020

«Я обнаружил, что это вызов .load (), который по какой-то причине его нарушает.»

Не уверен, что происходит, но ... Просто слушать loadedmetadata - это недостаточно, чтобы нарисовать изображение из видео. Метаданные анализируются, но что, если пиксели еще не декодированы и недоступны для снимка? Это даст вам нежелательный результат.

В приведенном ниже примере я изменил ваш код, чтобы прослушивать событие play, а затем рисовать видеокадр (ы). Другие идеи могут заключаться в том, чтобы загрузить + приостановить, перейти к предпочтительному времени, а затем нарисовать этот кадр в виде эскиза. ) внутри этой функции. Никакая другая функция не узнает, что означает ваш ctx, если вы определите его только внутри слушателя событий.

Ваш измененный код для тестирования:

const { useRef, useState } = React;
var videoRef;
var canvasRef;
var sourceRef;
var ctx;

var videoWidth;
var videoHeight;


function Thumbnail() 
{ 
    videoRef = useRef();
    canvasRef = useRef();
    sourceRef = useRef();

    const [urlSource, setUrlSource] = useState(null);

    function onUploadVideoChange(event) 
    {
        event.persist();

        const file = event.target.files[0];
        const isAllowed = file.type === 'video/mp4';

        if (!isAllowed) { alert('Only mp4 videos are allowed'); }

        else 
        {
            videoRef.current.setAttribute('src', URL.createObjectURL(file));
            videoRef.current.load();
            console.log('src', videoRef.current.src);

            videoRef.current.addEventListener('play', handle_media_events );

            videoRef.current.addEventListener('loadedmetadata', () => {
            const videoLength = videoRef.current.duration;
            console.log("onUploadVideoChange -> videoLength", videoLength)
            videoWidth = videoRef.current.videoWidth;
            console.log("onUploadVideoChange -> videoWidth", videoWidth)
            videoHeight = videoRef.current.videoHeight;
            console.log("onUploadVideoChange -> videoHeight", videoHeight)

            videoRef.current.currentTime = Math.floor(videoLength / 2);
            console.log('video', videoRef.current);
            ctx = canvasRef.current.getContext('2d');
            canvasRef.current.width = videoWidth;
            canvasRef.current.height = videoHeight;
          });
        }

    }

    return  ( 
                <div> 
                <input ref={videoRef} type="file" id="file" accept="video/mp4" onChange={onUploadVideoChange} />    
                <video ref={videoRef} controls> <source type="video/mp4" ref={sourceRef} /> </video>
                <canvas ref={canvasRef}></canvas>
                </div>
            ) 
}

function handle_media_events()
{
    if (event.type == "play") //# event can be "play", "pause", "seek", etc
    {
        //draw_video_Still(); //# for canvas with still image frame
        draw_video_Move(); //# for canvas with video motion
    }
}

function draw_video_Still()
{ 
    ctx.drawImage(videoRef.current, 0, 0, videoWidth, videoHeight);
}

function draw_video_Move()
{ 
    ctx.drawImage(videoRef.current, 0, 0, videoWidth, videoHeight);
    setTimeout( () => { draw_video_Move() }, 40 ); //# draw at every 40 millisecs   
}

ReactDOM.render(<Thumbnail/>, document.getElementById("app"));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...