Недавно я пытался сгенерировать видео в браузере и, таким образом, использовал два подхода:
MediaRecorder и canvas.captureStream. Подробнее здесь.Подход Whammy работает хорошо, но поддерживается только в Chrome, поскольку это единственный браузер, который в настоящее время поддерживает кодировку webp (canvas.toDataURL("image/webp")). Итак, я использую подход captureStream в качестве резервной копии для Firefox (и использую libwebpjs для Safari).
Итак, теперь перейдем к моему вопросу: есть ли способ контролировать качество видео в потоке холста? А если нет, то рассматривали ли браузеры / w3c что-то подобное?
Вот скриншот одного из кадров видео, созданного whammy:
А вот тот же кадр, сгенерированный подходом MediaRecorder/canvas.captureStream:
Моя первая мысль - искусственно увеличить разрешение холста, который я транслирую, но я не хочу, чтобы выходное видео было больше.
Я пробовал увеличить частоту кадров, передаваемую методу captureStream (думая, что может произойти какая-то странная интерполяция кадров), но это не помогает. Если я сделаю его слишком высоким, качество ухудшится. Моя текущая теория заключается в том, что браузер определяет качество потока в зависимости от того, к какой вычислительной мощности он имеет доступ. В этом есть смысл, потому что, если он будет соответствовать указанной мной частоте кадров, тогда что-то должно уступить.
Итак, следующая мысль заключается в том, что я должен снизить скорость, с которой я загружаю холст изображениями, а затем пропорционально снизить значение FPS, которое я передаю в captureStream, но проблема в том, что, хотя я, вероятно, решив проблему качества, я бы получил видео, которое работает медленнее, чем должно.
Редактировать:Вот грубый набросок кода, который я использую, на случай, если он поможет кому-нибудь в подобной ситуации.
Это артефакты сжатия, и я боюсь, что таких опций нет ... Итак, во-первых, это не из-за captureStream. Вы можете проверить это, передав свой поток напрямую srcObject объекта videoElement, и вы не заметите столько артефактов. Основная проблема заключается в том, что наиболее распространенные видеокодеки не предназначены для отображения такой графики, воспринимайте это как то, что делает JPEG. В MediaRecorder есть опция videoBitsPerSecond, но она, вероятно, здесь не поможет. (Я пробовал, но этого не произошло). В Chrome у меня были чуть менее ужасные результаты с использованием кодека vp8, чем с любым другим.
@HelderSepu Я попытался удалить ненужные части моего кода, поэтому в нем может быть пара ошибок: gist.github.com/josephrocca/ec073b3a90f936bec87bbd8e3e4c3486
Просто примечание о вашей сути: if (MediaRecorder) должен быть if (window.MediaRecorder), иначе вы выбросите ReferenceError, и вместо цикла setTimeout 1 мс вам лучше запустить requestAnimationFrame one (я не думаю, что вы все равно можете записывать со скоростью более 60 кадров в секунду )
Ах, спасибо за ловушку MeidiaRecorder. Причина, по которой я выбрал setTimeout, а не requestAnimationFrame, заключается в том, что я полагал, что последний более подвержен дросселированию браузером в случае задержки - я бы предпочел, чтобы браузер пользователя зависал, чем рисковал пропускать кадры. Я также не установил тайм-аут на 1/opts.fps, потому что решил, что в идеале мне следует обновлять холст намного быстрее, чем частота кадров captureStream, иначе я бы рискнул получить своего рода эффект временное алиасинг. Хотя я могу ошибаться.
setTimeout будет регулироваться так же, как rAF ... См. этот вопрос / ответ для альтернативного метода синхронизации, который не должен регулироваться. Но учтите, что это регулирование применяется только тогда, когда окно размыто. Если это происходит из-за занятости браузера, даже ваши рисунки на холсте все равно будут заблокированы.
Хорошо, переключил суть на requestAnimationFrame. Я провел несколько тестов, и, похоже, ни один из подходов не ограничен в Chrome или Firefox, когда вкладка / браузер не сфокусированы. Немного смущен этим.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это артефакты сжатия, и пока что вы мало что можете сделать ...
Видеокодеки созданы в основном для отображения реальных цветов и форм, что немного похоже на JPEG с очень низким качеством. Они также сделают все возможное, чтобы хранить как можно меньше информации между ключевыми кадрами (некоторые используют алгоритм обнаружения движения), чтобы им нужно было хранить меньше данных.
Эти кодеки обычно имеют некоторые настраиваемые параметры, которые позволяют нам улучшить постоянное качество кодирования, но спецификации MediaRecorder не зависят от кодеков, они не предоставляют (пока) возможность в API для нас, веб-разработчиков, для установки любых других вариант, чем фиксированный битрейт (который нам здесь больше не поможет).
Однако есть это предложение, который требует такой функции.
Спасибо, что изучили это! Приятно видеть, что этот материал обсуждается людьми w3c.
Мне любопытно, почему фиксированная скорость передачи данных (например, параметр videoBitsPerSecond в конструкторе MediaRecorder) не помогает улучшить качество здесь? Разве это не то, что предназначена для управления битрейтом? У меня должно быть какое-то недоразумение.
@Joe, во-первых, нет опции CBR, videoBitsPerSecond - это только целевая скорость любого режима (я думаю, обычно это VBR). Тогда я предполагаю, что качество видео в VP8 зависит от другого варианта: webmproject.org/docs/encoder-parameters
На самом деле, увеличение videoBitsPerSecond улучшает внешний вид
Вы можете поделиться своим кодом?