максимальный размер стека вызовов превышен при отображении видео с веб-камеры на холст - PullRequest
0 голосов
/ 22 февраля 2019

Я занимаюсь разработкой приложения, в котором будет два участника сеанса, и у них будет видеозвонок.В основном будет 3 видеопотока.Двое из участников и один будут совместно использовать экран.Эта часть уже работает, но когда пользователь нажимает на кнопку записи, эти 3 видео должны подаваться на холст, а когда пауза, то она должна быть приостановлена.Я пытаюсь отобразить только одно видео на холсте для проверки, если оно работает "RangeError: Maximum call stack size exceeded on draw function ".

const draw = (canva, context) => {
    console.log('localVideoRef', localVideoRef)
    context.drawImage(localVideoRef.current, 0, 0, canva.clientWidth, canva.clientHeight);
    console.log('context draw', context)
    requestAnimationFrame(draw(canva, context))
  }
  const handleRecord = () => {
    const canva = document.createElement('canvas');
    canva.id = "canvas";
    const context = canva.getContext("2d");
    canva.width = canva.clientWidth;
    canva.width = canva.clientHeight;
    console.log('canva', context, canva);
    console.log('room', room);
    draw(canva, context);
    requestAnimationFrame(draw(canva, context)) # above error is shown here
    console.log('canva after drawing image', canva);
  }

Ошибка в этой строке requestAnimationFrame(draw(canva, context))

Обновление (все еще работает непрерывно даже после остановкизапись)

let canva, context = null;

function App(props) {
  const [record, setRecord] = React.useState('');
  React.useEffect(() => {
    canva = document.createElement('canvas');
    canva.id = "canvas";
    context = canva.getContext("2d");
    canva.width = canva.clientWidth;
    canva.width = canva.clientHeight;
  }, [])
  React.useEffect(() => {
    console.log('record', record);
    if (record === 'start' || record === 'resume') {
      requestAnimationFrame(() => draw(canva, context));
      console.log('canva after paint video', canva);
    } else {
      // when pausing or stoping recording, the painting should not be done. 
      console.log('this is the canva after paused or stopped', canva)
    }

  }, [record])
  const draw = (canva, context) => {
    context.drawImage(localMediaRef.current, 0, 0, canva.clientWidth, canva.clientHeight);
    console.log('painting');
    requestAnimationFrame(() => draw(canva, context));
  }
  const handleRecord = (type) => {
    setRecord(type)
  }
  render {
    return (

    )
  }
}

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019
requestAnimationFrame(draw(canva, context))

Этот код будет немедленно вызывать рисование, и тогда любое возвращаемое значение рисования будет передано в requestAnimationFrame.Внутри draw вы повторяете этот процесс, немедленно вызывая draw, который немедленно вызывает draw и т. Д.

Вместо этого вы хотите передать функцию в кадр анимации запроса, например:

requestAnimationFrame(() => draw(canva, context));
0 голосов
/ 22 февраля 2019

Привет, это потому, что вы уже вызываете requestAnimationFrame() в своем коде draw().Следовательно, функция уже рекурсивна.Вызывая draw AND requestAnimationFrame(draw), вы вызываете 2 бесконечно рекурсивные функции одновременно.Просто удалите draw(), и он будет работать:

const draw = (canva, context) => {
    console.log('localVideoRef', localVideoRef)
    context.drawImage(localVideoRef.current, 0, 0, canva.clientWidth, canva.clientHeight);
    console.log('context draw', context)
    requestAnimationFrame( (timestamp)=>draw(canva, context) ); // EDITED AS PER @Nicholas' answer.
}
const handleRecord = () => {
    const canva = document.createElement('canvas');
    canva.id = "canvas";
    const context = canva.getContext("2d");
    canva.width = canva.clientWidth;
    canva.width = canva.clientHeight;
    console.log('canva', context, canva);
    console.log('room', room);
    //draw(canva, context);        //just remove this line
    requestAnimationFrame( (timestamp)=>draw(canva, context) ) // EDITED AS PER @Nicholas' answer.
    console.log('canva after drawing image', canva);
}

Проверьте документацию для получения более подробной информации о requestAnimationFrame.Обратите внимание, что в их, например, requestAnimationFrame(step) вызывается, но step() не вызывается.

Обновление: Как указывал @Nicholas, вам нужно обернуть свою функцию рисования в другую функцию,Это показано выше.

Что касается , почему вызывает ошибку maximum call size exceeded, я на самом деле немного запутался.Когда я тестировал неисправный код на консоли Chrome, вместо этого я получил эту ошибку:

Uncaught TypeError: Не удалось выполнить «requestAnimationFrame» в «Window»: обратный вызов, предоставленный в качестве параметра 1, не является функцией.

Это действительно правильно в теории.Думайте о requestAnimationFrame как о чем-то похожем на setTimeout.setTimeout использует обратный вызов как setTimeout(callback, time);;так же requestAnimationFrame.

Когда вы передаете requestAnimationFrame( draw(canva, context) ), вы в основном указываете функции requestAnimationFrame сделать что-то вроде draw(canva, context)() где-то в своем коде, а не draw(canva, context) как (Я думаю) вы ожидаете.Следовательно, он выдает ошибку callback provided is not a function на моей консоли Chrome.

Но что касается ошибки max call stack exceeded, я думаю, что ваш движок / компилятор JavaScript requestAnimationFrame перехватывает ошибку, игнорирует ее,и затем переходит к вызову функции отрисовки, как .Таким образом, это, в основном, означает:

draw = (canva, context)=>{
    ...
    draw(canva, context) //oh noes
}

Теперь это в основном бесконечно работающая рекурсивная функция .Следовательно, maximum call stack exceeded ошибка.

...