이제 많은 브라우저에서 사용자의 동영상 및 오디오 입력에 액세스할 수 있습니다. 그러나 브라우저에 따라 전체 동적 인라인 환경일 수도 있고 사용자 기기의 다른 앱에 위임될 수도 있습니다.
간단하게 시작하고 점진적으로 진행
가장 쉬운 방법은 사용자에게 사전 녹음된 파일을 요청하는 것입니다. 간단한 파일 입력 요소를 만들고 동영상 파일만 허용된다는 것을 나타내는 accept
필터와 카메라에서 직접 가져오려는 것을 나타내는 capture
속성을 추가하면 됩니다.
<input type="file" accept="video/*" capture />
이 메서드는 모든 플랫폼에서 작동합니다. 데스크톱에서는 사용자에게 파일 시스템에서 파일을 업로드하라는 메시지가 표시되며 capture
속성은 무시됩니다. iOS의 Safari에서는 카메라 앱이 열리므로 동영상을 녹화한 후 웹페이지로 다시 보낼 수 있습니다. Android에서는 동영상을 녹화할 앱을 선택한 후 웹페이지로 다시 보낼 수 있습니다.
많은 휴대기기에는 카메라가 2대 이상 있습니다. 원하는 경우 사용자를 향하는 카메라를 사용하려면 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
에 연결하여 서버에 업로드- 캔버스에 프레임을 그리고 필터를 적용합니다.
동영상 데이터에 액세스하는 입력 요소 메서드를 사용하는 것은 어디서나 볼 수 있지만 가장 매력적이지 않은 옵션입니다. 카메라에 액세스하여 페이지에서 바로 멋진 환경을 제공하고자 합니다.
대화형으로 카메라에 액세스
최신 브라우저는 카메라에 직접 연결할 수 있으므로 웹페이지와 완전히 통합되고 사용자가 브라우저를 벗어나지 않는 환경을 빌드할 수 있습니다.
카메라 액세스 권한 획득
WebRTC 사양의 getUserMedia()
라는 API를 사용하여 카메라에 직접 액세스할 수 있습니다. getUserMedia()
에서 사용자에게 연결된 마이크와 카메라에 대한 액세스 권한을 요청합니다.
성공하면 API는 카메라 또는 마이크의 데이터가 포함된 Stream
를 반환하며, 이를 <video>
요소에 연결하거나 WebRTC 스트림에 연결하거나 MediaRecorder
API를 사용하여 저장할 수 있습니다.
카메라에서 데이터를 가져오려면 getUserMedia()
API에 전달되는 제약 조건 객체에서 video: true
를 설정하기만 하면 됩니다.
<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
를 호출할 때 사용할 deviceId를 전달할 수 있습니다.
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,
);
두 경우 모두 재생 중인 동영상의 현재 프레임이 사용됩니다. 여러 프레임을 처리하려면 매번 동영상을 캔버스에 다시 그려야 합니다.
이미지 및 동영상에 실시간 효과 적용에 관한 도움말에서 자세히 알아보세요.
카메라의 데이터 저장
카메라의 데이터를 저장하는 가장 쉬운 방법은 MediaRecorder
API를 사용하는 것입니다.
MediaRecorder
API는 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
를 호출하는 즉시 브라우저에서 사용자에게 사이트에 카메라 액세스 권한을 부여하라는 메시지를 표시합니다.
사용자는 컴퓨터의 강력한 기기에 대한 액세스 권한을 요청하는 메시지가 표시되는 것을 싫어하며 요청을 자주 차단하거나 메시지가 생성된 컨텍스트를 이해하지 못하는 경우 무시합니다. 처음 필요할 때만 카메라 액세스를 요청하는 것이 가장 좋습니다. 사용자가 액세스 권한을 부여하면 다시 요청되지 않지만 사용자가 액세스 권한을 거부하면 다시 액세스하여 사용자에게 권한을 요청할 수 없습니다.
permissions API를 사용하여 이미 액세스 권한이 있는지 확인
getUserMedia
API는 이미 카메라에 액세스할 수 있는지 여부를 알려주지 않습니다. 여기서 문제가 발생합니다. 사용자가 카메라에 대한 액세스 권한을 부여하도록 하는 멋진 UI를 제공하려면 카메라에 대한 액세스 권한을 요청해야 합니다.
일부 브라우저에서는 Permission API를 사용하여 이 문제를 해결할 수 있습니다. navigator.permission
API를 사용하면 다시 메시지를 표시하지 않고도 특정 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 () {};
});