Многие браузеры теперь имеют возможность доступа к видео- и аудиовходу пользователя. Однако, в зависимости от браузера, это может быть полностью динамический и встроенный интерфейс или его можно делегировать другому приложению на устройстве пользователя.
Начните с простого и постепенно
Самый простой способ — просто попросить пользователя предоставить заранее записанный файл. Сделайте это, создав простой элемент ввода файла и добавив фильтр accept
, который указывает, что мы можем принимать только видеофайлы, и атрибут capture
, который указывает, что мы хотим получить его непосредственно с камеры.
<input type="file" accept="video/*" capture />
Этот метод работает на всех платформах. На рабочем столе пользователю будет предложено загрузить файл из файловой системы (игнорируя атрибут capture
). В Safari на iOS откроется приложение камеры, позволяющее записать видео, а затем отправить его обратно на веб-страницу; на Android пользователю предоставляется выбор, какое приложение использовать для записи видео перед отправкой его обратно на веб-страницу.
Многие мобильные устройства имеют более одной камеры. Если у вас есть предпочтения, вы можете установить атрибут capture
на user
, если вы хотите, чтобы камера была обращена к пользователю, или environment
, если вы хотите, чтобы камера была обращена наружу.
<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />
Обратите внимание: это всего лишь подсказка: если браузер не поддерживает эту опцию или тип камеры, который вы запрашиваете, недоступен, браузер может выбрать другую камеру.
Как только пользователь завершит запись и вернется на веб-сайт, вам нужно каким-то образом получить данные файла. Вы можете получить быстрый доступ, прикрепив событие onchange
к элементу ввода, а затем прочитав свойство files
объекта события.
<input type="file" accept="video/*" capture="camera" id="recorder" />
<video id="player" controls></video>
<script>
var recorder = document.getElementById('recorder');
var player = document.getElementById('player');
recorder.addEventListener('change', function (e) {
var file = e.target.files[0];
// Do something with the video file.
player.src = URL.createObjectURL(file);
});
</script>
Получив доступ к файлу, вы сможете делать с ним все, что захотите. Например, вы можете:
- Прикрепите его непосредственно к элементу
<video>
, чтобы его можно было воспроизвести. - Загрузите его на устройство пользователя
- Загрузите его на сервер, прикрепив к
XMLHttpRequest
- Нарисуйте кадры на холсте и примените к ним фильтры.
Хотя использование метода элемента ввода для получения доступа к видеоданным распространено повсеместно, это наименее привлекательный вариант. Мы очень хотим получить доступ к камере и обеспечить удобство работы прямо на странице.
Доступ к камере в интерактивном режиме
Современные браузеры могут иметь прямую связь с камерой, что позволяет нам создавать возможности, полностью интегрированные с веб-страницей, и пользователь никогда не покинет браузер.
Получите доступ к камере
Мы можем напрямую получить доступ к камере, используя API в спецификации WebRTC под названием getUserMedia()
. getUserMedia()
предложит пользователю доступ к подключенным микрофонам и камерам.
В случае успеха API вернет Stream
, который будет содержать данные с камеры или микрофона, и затем мы сможем либо прикрепить его к элементу <video>
, присоединить к потоку WebRTC, либо сохранить его с помощью API MediaRecorder
.
Чтобы получить данные с камеры, мы просто устанавливаем video: true
в объекте ограничений, который передается в API getUserMedia()
<video id="player" controls></video>
<script>
var player = document.getElementById('player');
var handleSuccess = function (stream) {
player.srcObject = stream;
};
navigator.mediaDevices
.getUserMedia({audio: true, video: true})
.then(handleSuccess);
</script>
Если вы хотите выбрать конкретную камеру, вы можете сначала перечислить доступные камеры.
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices = devices.filter((d) => d.kind === 'videoinput');
});
Затем вы можете передать идентификатор устройства, который хотите использовать, при вызове getUserMedia
.
navigator.mediaDevices.getUserMedia({
audio: true,
video: {
deviceId: devices[0].deviceId,
},
});
Само по себе это не так уж и полезно. Все, что мы можем сделать, это взять видеоданные и воспроизвести их.
Доступ к необработанным данным с камеры
Чтобы получить доступ к необработанным видеоданным с камеры, вы можете нарисовать каждый кадр в <canvas>
и напрямую манипулировать пикселями.
Для 2D-холста вы можете использовать метод контекста drawImage
, чтобы отрисовать текущий кадр элемента <video>
на холсте.
context.drawImage(myVideoElement, 0, 0);
Используя холст WebGL, вы можете использовать элемент <video>
в качестве источника текстуры.
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
myVideoElement,
);
Обратите внимание, что в любом случае будет использоваться текущий кадр воспроизводимого видео. Для обработки нескольких кадров необходимо каждый раз перерисовывать видео на холсте.
Подробнее об этом вы можете узнать в нашей статье о применении эффектов реального времени к изображениям и видео .
Сохраните данные с камеры
The easiest way to save the data from the camera is to use the MediaRecorder
API.
API MediaRecorder
возьмет поток, созданный getUserMedia
, а затем постепенно сохранит данные из потока в выбранное вами место назначения.
<a id="download">Download</a>
<button id="stop">Stop</button>
<script>
let shouldStop = false;
let stopped = false;
const downloadLink = document.getElementById('download');
const stopButton = document.getElementById('stop');
stopButton.addEventListener('click', function() {
shouldStop = true;
})
var handleSuccess = function(stream) {
const options = {mimeType: 'video/webm'};
const recordedChunks = [];
const mediaRecorder = new MediaRecorder(stream, options);
mediaRecorder.addEventListener('dataavailable', function(e) {
if (e.data.size > 0) {
recordedChunks.push(e.data);
}
if(shouldStop === true && stopped === false) {
mediaRecorder.stop();
stopped = true;
}
});
mediaRecorder.addEventListener('stop', function() {
downloadLink.href = URL.createObjectURL(new Blob(recordedChunks));
downloadLink.download = 'acetest.webm';
});
mediaRecorder.start();
};
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(handleSuccess);
</script>
В нашем случае мы сохраняем данные непосредственно в массив, который позже можем превратить в Blob
, который затем можно использовать для сохранения на нашем веб-сервере или непосредственно в хранилище на устройстве пользователя.
Спросите разрешения использовать камеру ответственно
Если пользователь ранее не предоставил вашему сайту доступ к камере, то в тот момент, когда вы вызываете getUserMedia
браузер предложит пользователю предоставить вашему сайту разрешение на использование камеры.
Пользователям ненавистно получать запросы на доступ к мощным устройствам на их компьютере, и они часто блокируют запрос или игнорируют его, если не понимают контекст, в котором был создан запрос. Лучше всего запрашивать доступ к камере только тогда, когда это необходимо. После того, как пользователь предоставил доступ, его больше не будут спрашивать, однако, если он отклонит доступ, вы не сможете снова получить доступ, чтобы запросить у пользователя разрешение.
Используйте API разрешений, чтобы проверить, есть ли у вас уже доступ
API getUserMedia
не дает вам информации о том, есть ли у вас уже доступ к камере. Это создает проблему: чтобы обеспечить приятный пользовательский интерфейс, позволяющий пользователю предоставить вам доступ к камере, вам нужно запросить доступ к камере.
В некоторых браузерах эту проблему можно решить с помощью API разрешений. API navigator.permission
позволяет вам запрашивать состояние возможности доступа к определенным API без необходимости повторного запроса.
Чтобы узнать, есть ли у вас доступ к камере пользователя, вы можете передать {name: 'camera'}
в метод запроса, и он вернет либо:
-
granted
— пользователь ранее предоставил вам доступ к камере; -
prompt
— пользователь не предоставил вам доступ и будет запрошен при вызовеgetUserMedia
; -
denied
— система или пользователь явно заблокировали доступ к камере, и вы не сможете получить к ней доступ.
И теперь вы можете быстро проверить, нужно ли вам изменить пользовательский интерфейс, чтобы учесть действия, которые должен выполнить пользователь.
navigator.permissions.query({name: 'camera'}).then(function (result) {
if (result.state == 'granted') {
} else if (result.state == 'prompt') {
} else if (result.state == 'denied') {
}
result.onchange = function () {};
});