Wiele przeglądarek ma teraz możliwość dostępu do wejścia wideo i audio od użytkownika. Jednak w zależności od przeglądarki może to być w pełni dynamiczne i zintegrowane środowisko lub może zostać przekazane do innej aplikacji na urządzeniu użytkownika.
Zacznij od czegoś prostego i stopniowo
Najprostszym rozwiązaniem jest poproszenie użytkownika o nagranie pliku. W tym celu utwórz prosty element wejściowy pliku i dodaj filtr accept, który wskazuje, że możemy akceptować tylko pliki wideo, oraz atrybut capture, który wskazuje, że chcemy pobierać je bezpośrednio z aparatu.
<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 (atrybut capture zostanie zignorowany). W Safari na iOS otworzy się aplikacja aparatu, która umożliwia nagranie filmu i odesłanie go na stronę internetową. Na Androidzie użytkownik może wybrać aplikację, w której chce nagrać film, zanim odeśle go na stronę internetową.
Wiele urządzeń mobilnych ma więcej niż 1 aparat. Jeśli masz preferencje, możesz ustawić atrybut capture na user, jeśli chcesz, aby kamera była skierowana na użytkownika, lub na environment, jeśli chcesz, aby kamera była skierowana na zewnątrz.
<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />
Pamiętaj, że to tylko wskazówka – jeśli przeglądarka nie obsługuje tej opcji lub żądany typ kamery jest niedostępny, przeglądarka może wybrać inną kamerę.
Gdy użytkownik zakończy nagrywanie i wróci do witryny, musisz w jakiś sposób uzyskać dostęp do danych pliku. Możesz uzyskać szybki dostęp, dołączając zdarzenie onchange do elementu wejściowego, a następnie odczytując 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 uzyskasz dostęp do pliku, możesz z nim zrobić, co chcesz. Możesz na przykład:
- Dołącz go bezpośrednio do elementu
<video>, aby można było go odtworzyć - pobrać go na urządzenie użytkownika,
- Prześlij go na serwer, dołączając do
XMLHttpRequest - Rysowanie klatek na obszarze roboczym i stosowanie do nich filtrów
Chociaż metoda uzyskiwania dostępu do danych wideo za pomocą elementu wejściowego jest powszechna, jest to najmniej atrakcyjna opcja. Chcemy uzyskać dostęp do kamery i zapewnić użytkownikom dobre wrażenia bezpośrednio na stronie.
Interaktywny dostęp do aparatu
Nowoczesne przeglądarki mogą mieć bezpośredni dostęp do aparatu, co pozwala nam tworzyć rozwiązania, które są w pełni zintegrowane ze stroną internetową i nie wymagają od użytkownika opuszczania przeglądarki.
Uzyskiwanie dostępu do aparatu
Możemy uzyskać bezpośredni dostęp do kamery, używając interfejsu API w specyfikacji WebRTC o nazwie getUserMedia(). getUserMedia() poprosi użytkownika o dostęp do podłączonych mikrofonów i kamer.
Jeśli się powiedzie, interfejs API zwróci obiekt Stream, który będzie zawierał dane z kamery lub mikrofonu. Możemy go następnie dołączyć do elementu <video>, dołączyć do strumienia WebRTC lub zapisać za pomocą interfejsu API MediaRecorder.
Aby pobrać dane z kamery, ustawiamy video: true w obiekcie ograniczeń, który jest przekazywany 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ć konkretną kamerę, możesz najpierw wyświetlić listę dostępnych kamer.
navigator.mediaDevices.enumerateDevices().then((devices) => {
devices = devices.filter((d) => d.kind === 'videoinput');
});
Następnie możesz przekazać identyfikator deviceId, którego chcesz użyć podczas wywoływania metody getUserMedia.
navigator.mediaDevices.getUserMedia({
audio: true,
video: {
deviceId: devices[0].deviceId,
},
});
Samo w sobie nie jest to zbyt przydatne. Możemy jedynie pobrać dane filmu i go odtworzyć.
dostęp do nieprzetworzonych danych z aparatu,
Aby uzyskać dostęp do nieprzetworzonych danych wideo z kamery, możesz narysować każdą klatkę w <canvas> i bezpośrednio manipulować pikselami.
W przypadku elementu canvas 2D możesz użyć metody drawImage kontekstu, aby narysować bieżącą klatkę elementu <video> w elemencie canvas.
context.drawImage(myVideoElement, 0, 0);
W przypadku obszaru roboczego 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,
);
Pamiętaj, że w obu przypadkach zostanie użyta bieżąca klatka odtwarzanego filmu. Aby przetworzyć wiele klatek, musisz za każdym razem ponownie narysować film na elemencie canvas.
Więcej informacji znajdziesz w artykule o stosowaniu efektów w czasie rzeczywistym do obrazów i filmów.
Zapisz dane z aparatu.
Najprostszym sposobem na zapisanie danych z kamery jest użycie interfejsu API MediaRecorder.
Interfejs API MediaRecorder pobierze strumień utworzony przez getUserMedia, a następnie będzie stopniowo zapisywać dane ze strumienia w preferowanym 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 zapisujemy dane bezpośrednio w tablicy, którą możemy później przekształcić w Blob, który można następnie zapisać na serwerze WWW lub bezpośrednio w pamięci urządzenia użytkownika.
Poproś o zgodę na odpowiedzialne korzystanie z aparatu
Jeśli użytkownik nie przyznał wcześniej Twojej witrynie dostępu do aparatu, w momencie wywołania getUserMedia przeglądarka poprosi użytkownika o przyznanie Twojej witrynie uprawnień do aparatu.
Użytkownicy nie lubią, gdy są proszeni o dostęp do zaawansowanych urządzeń na ich komputerze, i często blokują takie prośby lub je ignorują, jeśli nie rozumieją kontekstu, w którym zostały utworzone. Zgodnie ze sprawdzonymi metodami należy prosić o dostęp do aparatu tylko wtedy, gdy jest to konieczne. Gdy użytkownik przyzna dostęp, nie zostanie ponownie o niego poproszony. Jeśli jednak odrzuci prośbę, nie będzie można ponownie poprosić go o dostęp.
Używanie interfejsu API uprawnień do sprawdzania, czy masz już dostęp
Interfejs API getUserMedia nie informuje, czy masz już dostęp do kamery. To powoduje problem: aby wyświetlić ładny interfejs, który zachęci użytkownika do przyznania dostępu do aparatu, musisz poprosić o dostęp do aparatu.
W niektórych przeglądarkach można to rozwiązać za pomocą interfejsu Permission API. Interfejs API navigator.permission umożliwia sprawdzanie stanu dostępu do określonych interfejsów API bez konieczności ponownego wyświetlania prośby.
Aby sprawdzić, czy masz dostęp do kamery użytkownika, możesz przekazać {name: 'camera'} do metody zapytania, która zwróci jedną z tych wartości:
granted– użytkownik wcześniej przyznał Ci dostęp do kamery;prompt– użytkownik nie przyznał Ci dostępu i zostanie o to poproszony, gdy wywołaszgetUserMedia;denied– system lub użytkownik wyraźnie zablokował dostęp do aparatu i nie będziesz mieć do niego dostępu.
Możesz teraz szybko sprawdzić, czy musisz zmienić interfejs, aby dostosować go do działań, 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 () {};
});