В языке HTML5 появились API для доступа к аппаратному обеспечению устройств, включая MediaDevices API. Этот API предоставляет доступ к устройствам ввода мультимедиа. в том числе аудио и видео.
С помощью этого API разработчики могут получать доступ к устройствам аудио и видео для трансляции и вывода видеопотоков в реальном времени в браузере. В этом учебном модуле вы научитесь получать доступ к видеопотокам с устройства пользователя и выводить его в браузере, используя метод getUserMedia
.
getUserMedia
API использует устройства ввода мультимедиа для получения потока MediaStream. Этот поток MediaStream содержит запрошенные типы мультимедиа, то есть аудио или видео. С помощью API можно выводить видеопотоки через браузер, что можно использовать для связи в реальном времени через браузер.
При использовании вместе с MediaStream Recording API вы можете записывать и сохранять мультимедийные данные, полученные через браузер. Этот API работает только с безопасными источниками, как и остальные новые API, а также работает с localhost
и файловыми URL.
В начале этого учебного модуля мы объясним концепции и продемонстрируем примеры с помощью Codepen. На заключительном шаге вы создадите рабочий видеопоток в браузере.
Вначале мы проверим, поддерживает ли браузер пользователя mediaDevices
API. Этот API существует в интерфейсе navigator и содержит текущее состояние и идентификатор пользовательского агента. Для проверки используется следующий код, который можно вставить в Codepen:
if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) {
console.log("Let's get this party started")
}
Вначале проверяется наличие mediaDevices
API в navigator
, а затем проверяется доступность getUserMedia
API в mediaDevices
. Если возвращается результат true
, можно начинать работу.
После подтверждения поддержки getUserMedia
в браузере необходимо запросить разрешение на использование устройств ввода мультимедиа на пользовательском агенте. Обычно после предоставления пользователем разрешения возвращается промис
, который разрешается в мультимедийный поток. Если пользователь не дает разрешения, этот промис
не возвращается, и доступ к данным устройствам блокируется.
Вставьте в Codepen следующую строку, чтобы запросить разрешение:
navigator.mediaDevices.getUserMedia({video: true})
Объект, предоставляемый как аргумент для метода getUserMedia
называется constraints
(переводится как ограничения). Он определяет, к каким устройствам ввода мультимедиа вы запрашиваете разрешение на доступ. Например, если объект содержит текст audio: true
, у пользователя запрашивается доступ к устройству ввода аудио.
В этом разделе мы расскажем о концепции contraints
. Объект constraints
— это объект MediaStreamConstraints
, который указывает типы мультимедиа для запроса и требования каждого типа мультимедиа. Вы можете использовать объект constraints
, чтобы указать требования к запрошенному потоку, например, требуемое разрешение (front
, back
).
При отправке этого запроса следует указать аргумент audio
или video
. Если запрошенные типы мультимедиа не будут найдены в браузере пользователя, будет выведено сообщение об ошибке NotFoundError
.
Если вы планируете запросить видеопоток м разрешением 1280 x 720
, вы можете обновить объект constraints
, чтобы он выглядел так:
{
video: {
width: 1280,
height: 720,
}
}
С этим обновлением браузер попробует подобрать заданные настройки качества для потока. Если видеоустройство не сможет обеспечить это разрешение, браузер возвратит другие доступные разрешения.
Чтобы браузер гарантированно возвращал разрешение не ниже указанного, вам нужно будет использовать свойство min
. Здесь вы можете обновить объект constraints
, добавив в него свойство min
:
{
video: {
width: {
min: 1280,
},
height: {
min: 720,
}
}
}
Это обеспечит возвращаемое разрешение потока не ниже 1280 x 720
. Если это минимальное требование не удастся выполнить, промис будет отклонен с сообщением об ошибке OverconstrainedError
.
В некоторых случаях вас может беспокоить сохранение данных и необходимость не превышать заданное разрешение потока. Это может быть полезно, если пользователь использует лимитированный тарифный план. Для реализации этой функции следует обновить объект constraints, добавив в него поле max
:
{
video: {
width: {
min: 1280,
max: 1920,
},
height: {
min: 720,
max: 1080
}
}
}
При таких параметрах браузер будет использовать разрешение видеопотока не менее 1280 x 720
и не более 1920 x 1080
.
Также можно использовать аргументы exact
и ideal
. Параметр ideal
обычно используется со свойствами min
и max
для подбора наилучших возможных настроек, ближайших к идеальному значению.
Вы можете обновить объект constraints для использования ключевого слова ideal
:
{
video: {
width: {
min: 1280,
ideal: 1920,
max: 2560,
},
height: {
min: 720,
ideal: 1080,
max: 1440
}
}
}
Чтобы указать браузеру использовать фронтальную или заднюю камеру (на мобильных устройствах), вы можете указать свойство facingMode
в объекте video
:
{
video: {
width: {
min: 1280,
ideal: 1920,
max: 2560,
},
height: {
min: 720,
ideal: 1080,
max: 1440
},
facingMode: 'user'
}
}
При этой настройке на всех устройствах всегда будет использоваться фронтальная камера. Чтобы использовать заднюю камеру мобильных устройств. вы можете изменить значение свойства facingMode
на environment
.
{
video: {
...
facingMode: {
exact: 'environment'
}
}
}
enumerateDevices
При вызове метода enumerateDevices
возвращаются все доступные на компьютере пользователя устройства ввода мультимедиа.
С помощью этого метода можно дать пользователю возможность выбрать устройство ввода мультимедиа для трансляции аудио- или видеоконтента. Этот метод возвращает промис
, разрешающийся в массив MediaDeviceInfo, который содержит информацию о каждом устройстве.
Ниже приведен фрагмент кода с примером использования этого метода:
async function getDevices() {
const devices = await navigator.mediaDevices.enumerateDevices();
}
Образец ответа для каждого из устройств выглядит следующим образом:
{
deviceId: "23e77f76e308d9b56cad920fe36883f30239491b8952ae36603c650fd5d8fbgj",
groupId: "e0be8445bd846722962662d91c9eb04ia624aa42c2ca7c8e876187d1db3a3875",
kind: "audiooutput",
label: "",
}
Примечание. Ярлык не возвращается, если отсутствует доступный поток, или если пользователь не предоставит разрешения на доступ к устройству.
Вы выполнили процедуру запроса и получения доступа к мультимедийным устройствам, настроили объект constraints для добавления требуемых разрешений и выбрали камеру, которая потребуется для записи видео.
После выполнения всех этих шагов нам нужно будет посмотреть соответствие потока трансляции заданным параметрам. Для этого мы используем элемент <video>
, чтобы вывести видеопоток в браузере.
Как уже говорилось ранее. метод getUserMedia
возвращает промис
, который может быть разрешен в поток. Возвращаемый поток можно конвертировать в URL объекта, используя метод createObjectURL
. Этот URL будет установлен как источник видео.
Вы создадите короткую демонстрационную программу, где пользователь сможет выбрать доступное видеоустройство из списка, используя метод enumerateDevices
.
Это метод navigator.mediaDevices
. Он перечисляет доступные мультимедийные устройства, в том числе микрофоны и камеры. Он возвращает промис
, который разрешается в массив объектов с подробными сведениями о доступных мультимедийных устройствах.
Создайте файл index.html
и обновите его содержимое с помощью следующего кода:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div class="display-cover">
<video autoplay></video>
<canvas class="d-none"></canvas>
<div class="video-options">
<select name="" id="" class="custom-select">
<option value="">Select camera</option>
</select>
</div>
<img class="screenshot-image d-none" alt="">
<div class="controls">
<button class="btn btn-danger play" title="Play"><i data-feather="play-circle"></i></button>
<button class="btn btn-info pause d-none" title="Pause"><i data-feather="pause"></i></button>
<button class="btn btn-outline-success screenshot d-none" title="ScreenShot"><i data-feather="image"></i></button>
</div>
</div>
<script src="https://unpkg.com/feather-icons"></script>
<script src="script.js"></script>
</body>
</html>
В приведенном выше фрагменте кода вы настроили требуемые элементы и пару элементов управления видео. Также мы добавили кнопку для снимков экрана текущего видеопотока.
Теперь применим к этим компонентам стили.
Создайте файл style.css
и скопируйте в него следующие стили. Мы включили Bootstrap, чтобы сократить объем кода CSS, который нужно будет написать для работы компонентов.
.screenshot-image {
width: 150px;
height: 90px;
border-radius: 4px;
border: 2px solid whitesmoke;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);
position: absolute;
bottom: 5px;
left: 10px;
background: white;
}
.display-cover {
display: flex;
justify-content: center;
align-items: center;
width: 70%;
margin: 5% auto;
position: relative;
}
video {
width: 100%;
background: rgba(0, 0, 0, 0.2);
}
.video-options {
position: absolute;
left: 20px;
top: 30px;
}
.controls {
position: absolute;
right: 20px;
top: 20px;
display: flex;
}
.controls > button {
width: 45px;
height: 45px;
text-align: center;
border-radius: 100%;
margin: 0 6px;
background: transparent;
}
.controls > button:hover svg {
color: white !important;
}
@media (min-width: 300px) and (max-width: 400px) {
.controls {
flex-direction: column;
}
.controls button {
margin: 5px 0 !important;
}
}
.controls > button > svg {
height: 20px;
width: 18px;
text-align: center;
margin: 0 auto;
padding: 0;
}
.controls button:nth-child(1) {
border: 2px solid #D2002E;
}
.controls button:nth-child(1) svg {
color: #D2002E;
}
.controls button:nth-child(2) {
border: 2px solid #008496;
}
.controls button:nth-child(2) svg {
color: #008496;
}
.controls button:nth-child(3) {
border: 2px solid #00B541;
}
.controls button:nth-child(3) svg {
color: #00B541;
}
.controls > button {
width: 45px;
height: 45px;
text-align: center;
border-radius: 100%;
margin: 0 6px;
background: transparent;
}
.controls > button:hover svg {
color: white;
}
Следующий шаг — добавление функционала в демонстрацию. Используя метод enumerateDevices
, вы получите доступные видеоустройства и зададите их как опции выбранного элемента. Создайте файл script.js
и добавьте в него следующий код:
feather.replace();
const controls = document.querySelector('.controls');
const cameraOptions = document.querySelector('.video-options>select');
const video = document.querySelector('video');
const canvas = document.querySelector('canvas');
const screenshotImage = document.querySelector('img');
const buttons = [...controls.querySelectorAll('button')];
let streamStarted = false;
const [play, pause, screenshot] = buttons;
const constraints = {
video: {
width: {
min: 1280,
ideal: 1920,
max: 2560,
},
height: {
min: 720,
ideal: 1080,
max: 1440
},
}
};
const getCameraSelection = async () => {
const devices = await navigator.mediaDevices.enumerateDevices();
const videoDevices = devices.filter(device => device.kind === 'videoinput');
const options = videoDevices.map(videoDevice => {
return `<option value="${videoDevice.deviceId}">${videoDevice.label}</option>`;
});
cameraOptions.innerHTML = options.join('');
};
play.onclick = () => {
if (streamStarted) {
video.play();
play.classList.add('d-none');
pause.classList.remove('d-none');
return;
}
if ('mediaDevices' in navigator && navigator.mediaDevices.getUserMedia) {
const updatedConstraints = {
...constraints,
deviceId: {
exact: cameraOptions.value
}
};
startStream(updatedConstraints);
}
};
const startStream = async (constraints) => {
const stream = await navigator.mediaDevices.getUserMedia(constraints);
handleStream(stream);
};
const handleStream = (stream) => {
video.srcObject = stream;
play.classList.add('d-none');
pause.classList.remove('d-none');
screenshot.classList.remove('d-none');
streamStarted = true;
};
getCameraSelection();
В приведенном выше фрагменте кода выполняется ряд действий. Давайте рассмотрим их подробнее:
feather.replace()
: этот метод создает экземпляр feather, набора иконок для веб-разработки.constraints
хранит начальную конфигурацию видеопотока. Она будет расширена, и в нее будет добавлено выбранное пользователем мультимедийное устройство.getCameraSelection
: данная функция вызывает метод enumerateDevices
. Затем мы выполняем фильтрацию массива на основе разрешенного промиса
, и выбираем устройства ввода видео. Из отфильтрованных результатов вы создаете <option>
для элемента <select>
.getUserMedia
выполняется в средстве прослушивания onclick
кнопки play
. Здесь перед началом трансляции мы проверяем, поддерживает ли браузер пользователя этот метод.startStream
, принимающую аргумент constraints
. Она вызывает метод getUserMedia
с указанными constraints
. handleStream
вызывается на основе трансляции из разрешенного промиса
. Этот метод устанавливает возвращаемый поток для объекта srcObject
видеоэлемента.Далее мы добавим средства прослушивания нажатий в элементы управления кнопками на страницах для приостановки
, остановки
и снимков экрана
. Также вы добавите средство прослушивания в элемент <select>
, чтобы обновить ограничения трансляции для выбранного видеоустройства.
Добавьте в файл script.js
следующий код:
...
cameraOptions.onchange = () => {
const updatedConstraints = {
...constraints,
deviceId: {
exact: cameraOptions.value
}
};
startStream(updatedConstraints);
};
const pauseStream = () => {
video.pause();
play.classList.remove('d-none');
pause.classList.add('d-none');
};
const doScreenshot = () => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0);
screenshotImage.src = canvas.toDataURL('image/webp');
screenshotImage.classList.remove('d-none');
};
pause.onclick = pauseStream;
screenshot.onclick = doScreenshot;
Теперь, когда вы откроете файл index.html
в браузере, при нажатии Play начнется трансляция.
Вот полная версия демонстрационной программы:
https://codepen.io/chrisbeast/pen/ebYwpX
В этом учебном модуле мы познакомились с getUserMedia
API. Это интересное дополнение HTML5, упрощающее захват мультимедийного контента через интернет.
Данный API принимает параметр (constraints
), который можно использовать для настройки доступа к устройствам ввода звука и видео. Также его можно использовать, чтобы задать требуемое разрешение видео для вашего приложения.
Вы можете расширить демонстрацию и предоставить пользователю возможность сохранить сделанные снимки экрана, а также записывать и сохранять аудио- и видеоданные с помощью MediaStream Recording API.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!