Wiele przeglądarek ma teraz możliwość dostępu do danych wejściowych wideo i dźwięku od użytkownika. Jednak w zależności od przeglądarki może to być pełne, dynamiczne wrażenia w ramach strony lub funkcja delegowana do innej aplikacji na urządzeniu użytkownika.
Zacznij od prostych działań i stopniowo je rozwijaj
Najłatwiej jest poprosić użytkownika o wcześniej nagrany plik. Aby to zrobić, utwórz prosty element wejścia pliku i dodaj filtr accept
, który wskazuje, że akceptujemy tylko pliki wideo, oraz atrybut capture
, który wskazuje, że chcemy pobrać plik bezpośrednio z kamery.
<input type="file" accept="video/*" capture />
Ta metoda działa na wszystkich platformach. Na komputerze użytkownik zostanie poproszony o przesłanie pliku z systemu plików (ignorując atrybut capture
). W Safari na iOS otworzy aplikację aparatu, która umożliwi Ci nagranie filmu, a potem wysłanie go z powrotem na stronę internetową. W przypadku Androida użytkownik będzie mógł wybrać aplikację, w której nagra film, zanim zostanie on wysłany z powrotem na stronę internetową.
Wiele urządzeń mobilnych ma więcej niż 1 kamerę. Jeśli chcesz, aby kamera była skierowana na użytkownika, możesz ustawić atrybut capture
na user
, a jeśli chcesz, aby kamera była skierowana na zewnątrz, na environment
.
<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />
Pamiętaj, że jest to tylko sugestia. Jeśli przeglądarka nie obsługuje tej opcji lub wybrany typ kamery jest niedostępny, może wybrać inną kamerę.
Gdy użytkownik zakończy nagrywanie i wróci do witryny, musisz w jakiś sposób uzyskać dane pliku. Aby uzyskać szybki dostęp, do elementu wejściowego dołącz zdarzenie onchange
, a potem odczytaj właściwość files
obiektu zdarzenia.
<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>
Gdy masz dostęp do pliku, możesz z nim zrobić wszystko, co chcesz. Możesz na przykład:
- Dołącz go bezpośrednio do elementu
<video>
, aby móc go odtworzyć. - Pobierz na urządzenie użytkownika.
- Prześlij go na serwer, dołączając do
XMLHttpRequest
- Rysowanie ramek na płótnie i stosowanie do nich filtrów
Chociaż metoda dostępu do danych wideo za pomocą elementu wejściowego jest powszechna, jest to najmniej atrakcyjna opcja. Bardzo zależy nam na dostępie do kamery, aby zapewnić użytkownikom wygodę bezpośrednio na stronie.
Interaktywny dostęp do kamery
Nowoczesne przeglądarki mogą mieć bezpośredni dostęp do aparatu, co pozwala nam tworzyć wrażenia, które są w pełni zintegrowane ze stroną internetową, a użytkownik nie musi opuszczać przeglądarki.
Uzyskiwanie dostępu do aparatu
Możemy uzyskać dostęp do kamery bezpośrednio za pomocą interfejsu API w specyfikacji WebRTC o nazwie getUserMedia()
. getUserMedia()
poprosi użytkownika o dostęp do podłączonych mikrofonów i kamer.
W przypadku powodzenia interfejs API zwróci obiekt Stream
, który będzie zawierać dane z kamery lub mikrofonu. Następnie możemy go dołączyć do elementu <video>
, do strumienia WebRTC lub zapisać za pomocą interfejsu API MediaRecorder
.
Aby pobrać dane z kamery, ustawiamy parametr video: true
w obiekcie ograniczeń przekazywanym do interfejsu 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>
Jeśli chcesz wybrać konkretny aparat, możesz najpierw przejrzeć dostępne kamery.
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices = devices.filter((d) => d.kind === 'videoinput');
});
Następnie możesz przekazać identyfikator urządzenia, którego chcesz użyć, gdy wywołasz funkcję getUserMedia
.
navigator.mediaDevices.getUserMedia({
audio: true,
video: {
deviceId: devices[0].deviceId,
},
});
Samo w sobie nie jest zbyt przydatne. Możemy tylko pobrać dane wideo i je odtworzyć.
Uzyskiwanie dostępu do nieprzetworzonych danych z aparatu
Aby uzyskać dostęp do nieprzetworzonych danych wideo z kamery, możesz narysować każdą klatkę w pliku <canvas>
i bezpośrednio manipulować pikselami.
W przypadku obrazu 2D możesz użyć metody drawImage
kontekstu, aby narysować bieżący kadr elementu <video>
na płótnie.
context.drawImage(myVideoElement, 0, 0);
W przypadku kanwy WebGL możesz użyć elementu <video>
jako źródła tekstury.
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
gl.RGBA,
gl.UNSIGNED_BYTE,
myVideoElement,
);
W obu przypadkach zostanie użyty bieżący kadr odtwarzanego filmu. Aby przetworzyć wiele klatek, musisz za każdym razem ponownie narysować film na płótnie.
Więcej informacji znajdziesz w artykule o zastosowaniu efektów w czasie rzeczywistym do zdjęć i filmów.
Zapisz dane z kamery
Najprostszym sposobem zapisywania danych z kamery jest użycie interfejsu API MediaRecorder
.
Interfejs API MediaRecorder
pobierze strumień utworzony przez getUserMedia
, a potem stopniowo zapisze dane ze strumienia w wybranym przez Ciebie miejscu docelowym.
<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>
W naszym przypadku dane są zapisywane bezpośrednio w tablicy, którą później możemy przekształcić w Blob
, a następnie zapisać na serwerze WWW lub bezpośrednio w pamięci na urządzeniu użytkownika.
Prośba o dostęp do kamery
Jeśli użytkownik nie zezwolił wcześniej Twojej witrynie na dostęp do kamery, gdy wywołasz funkcję getUserMedia
, przeglądarka poprosi użytkownika o przyznanie Twojej witrynie dostępu do kamery.
Użytkownicy nie lubią otrzymywać prośby o dostęp do zaawansowanych urządzeń na swoim komputerze. Często blokują one prośbę lub ignorują ją, jeśli nie rozumieją kontekstu, w którym została utworzona. Sprawdzoną metodą jest proszenie o dostęp do kamery tylko wtedy, gdy jest to konieczne. Gdy użytkownik przyzna dostęp, nie będziesz musiał ponownie prosić o pozwolenie. Jeśli jednak odmówi, nie będziesz mieć możliwości ponownego zapytania o dostęp.
.Używanie interfejsu API uprawnień do sprawdzenia, czy masz już dostęp
Interfejs API getUserMedia
nie informuje, czy masz już dostęp do kamery. To stwarza problem. Aby zapewnić ładny interfejs użytkownika i zachęcić użytkownika do przyznania dostępu do aparatu, musisz poprosić o taki dostęp.
W niektórych przeglądarkach można to rozwiązać, korzystając z interfejsu Permission API. Interfejs API navigator.permission
umożliwia wysyłanie zapytań o stan możliwości dostępu do określonych interfejsów API bez konieczności ponownego wyświetlania prośby.
Aby sprawdzić, czy masz dostęp do aparatu użytkownika, możesz przekazać parametr {name: 'camera'}
do metody zapytania. W zależności od tego, co zwróci:
granted
– użytkownik wcześniej przyznał Ci dostęp do kamery;prompt
– użytkownik nie przyznał Ci dostępu i zostanie poproszony o to podczas rozmowy telefonicznejgetUserMedia
;denied
– system lub użytkownik zablokował dostęp do kamery i nie będziesz mieć do niej dostępu.
Możesz teraz szybko sprawdzić, czy musisz zmienić interfejs, aby uwzględnić działania, które musi wykonać użytkownik.
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 () {};
});