Nagrywanie filmu wideo przez użytkownika

Mat Scales

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. Wystarczy, że utworzysz prosty element do wprowadzania danych do pliku i dodasz filtr accept wskazujący, że akceptujemy tylko pliki wideo, oraz atrybut capture, który wskazuje, że chcemy pobierać dane 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 w systemie iOS otworzy się aplikacja kamery, która pozwala nagrać film i odesłać go z powrotem na stronę internetową. Na Androidzie użytkownik wybierze aplikację, w której ma nagrać film, zanim prześle go 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. Jeśli chcesz, aby kamera była skierowana na zewnątrz, ustaw atrybut capture 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>

Po uzyskaniu dostępu do pliku możesz robić z nim, 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 na serwer, dołączając do XMLHttpRequest
  • Rysowanie ramek na płótnie i stosowanie do nich filtrów

Chociaż metoda dostępu do danych filmu 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 link do kamery, co pozwala nam tworzyć środowiska, które są w pełni zintegrowane ze stroną internetową, a użytkownik nigdy nie 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 wyświetlić listę dostępnych kamer.

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 <canvas> i bezpośrednio manipulować pikselami.

W przypadku obszaru roboczego 2D możesz użyć metody drawImage kontekstu, aby narysować bieżącą klatkę elementu <video> w obszarze roboczym.

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 stosowaniu efektów w czasie rzeczywistym do obrazów i filmów.

Zapisuj 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 z tego 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.

Poproś o pozwolenie na odpowiedzialne korzystanie z kamery

Jeśli użytkownik nie zezwolił wcześniej Twojej witrynie na dostęp do aparatu, to gdy wywołasz funkcję getUserMedia, przeglądarka poprosi użytkownika o przyznanie Twojej witrynie dostępu do aparatu.

Użytkownicy nie lubią otrzymywać prośby o dostęp do zaawansowanych urządzeń na swoim komputerze. Często blokują takie prośby lub ignorują je, jeśli nie rozumieją kontekstu, w którym zostały utworzone. 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 poproszenia o dostęp.

.

Użyj interfejsu IAM API, aby sprawdzić, 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 udzielenia 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 pytania.

Aby zapytać, czy masz dostęp do kamery użytkownika, możesz przekazać do metody zapytania polecenie {name: 'camera'}, które zwróci jeden z tych wyników:

  • 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 telefonicznej getUserMedia;
  • 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 () {};
});

Prześlij opinię