Кадры, снятые с веб-камеры, обработанные и нарисованные на холсте, отображаются в MacOS Safari не по порядку - PullRequest
0 голосов
/ 18 февраля 2019

tl; dr

См. Вариант B для моего кода.
GIF в разделе Phenomenon показывает проблему.
Только в Safari.

Справочная информация

Я создаю демонстрацию машинного обучения через Интернет.Демонстрация фиксирует локальную прямую трансляцию веб-камеры от пользователя, обрабатывает изображение (придумайте что-то вроде поиска лица, а затем запустите несколько сверточных нейронных сетей на изображении).Затем отображает результаты (например, лицо, выделенное прямоугольником, и некоторый текст) пользователю, например, зеркало.

Чтобы получить представление, представьте что-то вроде этого: https://tastenkunst.github.io/brfv4_javascript_examples/
(Этоэто не мое приложение, просто пример. На данный момент я не могу поделиться своим настоящим приложением.)

Цель

  • Захват изображения с веб-камеры.
  • Выполните некоторые длительные вычисления для захваченного изображения.
  • Отображение изображения (захваченного на шаге 1) и результатов расчета на холсте.
  • Повтор.

Контекст

Safari 12.0.2 с macOS Mojave на MBP 2018 (проблема также возникает на нескольких старых MacBook, которые я пробовал).

Инициализация (чтобы дать контекст для примеров):

const stream = await navigator.mediaDevices.getUserMedia({
    video: { width: 320, height: 240 }
});
video.srcObject = stream;
video.setAttribute("playsinline", "true");
await video.play();

captureImage() означает следующее:

tempCanvasCtx.drawImage(video, 0, 0);
const image = tempCanvasCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);

longCalculation(): может варьироваться по продолжительности (на кадр, а также в зависимости от машины) от моментов до 0,5 секунды.Он использует TensorFlow.js, работающий на графическом процессоре, и некоторые другие вычисления шейдеров WebGL (независимо от холстов).

video - это HTMLVideoElement, а ctx и tempCanvasCtx - это двухмерные контексты двух разныххолсты.Код находится внутри асинхронной функции.

Trials

Опция A

const loop = async () => {
    const image = captureImage();
    const result = await longCalculation(image);
    ctx.putImageData(image, 0, 0);

    requestAnimationFrame(loop);
};

requestAnimationFrame(loop);

Мое первое очевидное решение, которое работает во всех основных браузерах,кроме сафари.В Safari он является неопределенным, иногда работает, а иногда видео останавливается навсегда, возможно, из-за выполнения RAF, которое иногда занимает много времени и глушит RAF.

Опция B

const loop = async () => {
    const image = captureImage();
    const result = await longCalculation(image);
    ctx.putImageData(image, 0, 0);

    setTimeout(loop, 0);
};

setTimeout(loop, 0);

В этом случае происходит следующее:

Феномен

Полученное видео, отображаемое на холсте, не сохраняет последовательный порядок кадров.Предыдущие кадры иногда появляются позже и наоборот.Он прыгает вперед и назад на несколько секунд, иногда больше.Это дает действительно жуткий эффект, похожий на кассету в фильме «Кольцо», когда в одном кадре маленькая девочка стоит где-то, а в следующем - где-то совсем другое.Если вы записываете наручные часы, секундная стрелка будет прыгать вперед и назад.

example

Опция C

while (true) {
    const image = captureImage();
    const result = await longCalculation(image);
    ctx.putImageData(image, 0, 0);

    await new Promise(resolve => setTimeout(resolve, 0));
}

Я не уверен, отличаются ли B и C от других, но я включил их для прозрачности.

Я подумал, что то, о чем я прошу, должно быть простым ... Захват кадра и просто ожидание, пока он не будет обработан иотображается перед захватом и обработкой следующего кадра.Я не вижу, где что-то идет не так.

Я уже пробовал:

  • Увеличение времени ожидания, добавление дополнительных ожиданий (хотя работа медленнее, чем машина способнане желательное решение).
  • Создание и обработка очереди кадров.
  • Два уровня вложенности requestAnimationFrame с.
  • Регистрация времени событий (захвачено, нарисованономер кадра № и т. д.), который идет в хорошем порядке в консоли.Никогда не бывает более одного кадра в «очереди».
  • Рисование результатов в отдельном RAF.

Обратите внимание, что это может быть ошибкой в ​​самом Safari, так как я 'Я видел это явление на других сайтах (в частности, видеопроигрыватель Coursera), но тем не менее я все еще заинтересован в обходном пути.

Спасибо.

...