Merekam video dari pengguna

Mat Scales

Banyak browser kini memiliki kemampuan untuk mengakses input video dan audio dari pengguna. Namun, bergantung pada browser, pengalaman ini mungkin berupa pengalaman dinamis dan inline penuh, atau dapat didelegasikan ke aplikasi lain di perangkat pengguna.

Mulai dengan sederhana dan progresif

Hal termudah yang dapat dilakukan adalah meminta file yang telah direkam sebelumnya kepada pengguna. Lakukan ini dengan membuat elemen input file sederhana dan menambahkan filter accept yang menunjukkan bahwa kita hanya dapat menerima file video dan atribut capture yang menunjukkan bahwa kita ingin mendapatkannya langsung dari kamera.

<input type="file" accept="video/*" capture />

Metode ini berfungsi di semua platform. Di desktop, pengguna akan diminta untuk mengupload file dari sistem file (mengabaikan atribut capture). Di Safari pada iOS, aplikasi kamera akan terbuka, sehingga Anda dapat merekam video, lalu mengirimkannya kembali ke halaman web; di Android, pengguna akan diberi pilihan aplikasi yang akan digunakan untuk merekam video sebelum mengirimkannya kembali ke halaman web.

Banyak perangkat seluler memiliki lebih dari satu kamera. Jika Anda memiliki preferensi, Anda dapat menetapkan atribut capture ke user, jika Anda menginginkan kamera yang menghadap ke pengguna, atau environment jika Anda menginginkan kamera yang menghadap ke luar.

<input type="file" accept="video/*" capture="user" />
<input type="file" accept="video/*" capture="environment" />

Perhatikan bahwa ini hanyalah petunjuk - jika browser tidak mendukung opsi tersebut, atau jenis kamera yang Anda minta tidak tersedia, browser dapat memilih kamera lain.

Setelah pengguna selesai merekam dan kembali ke situs, Anda harus mendapatkan data file. Anda bisa mendapatkan akses cepat dengan melampirkan peristiwa onchange ke elemen input, lalu membaca properti files objek peristiwa.

<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>

Setelah memiliki akses ke file, Anda dapat melakukan apa pun yang Anda inginkan dengan file tersebut. Misalnya, Anda dapat:

  • Lampirkan langsung ke elemen <video> agar Anda dapat memutarnya
  • Mendownloadnya ke perangkat pengguna
  • Upload ke server dengan melampirkan ke XMLHttpRequest
  • Menggambar frame ke dalam kanvas dan menerapkan filter ke kanvas tersebut

Meskipun penggunaan metode elemen input untuk mendapatkan akses ke data video sudah umum, metode ini adalah opsi yang paling tidak menarik. Kami benar-benar ingin mendapatkan akses ke kamera dan memberikan pengalaman yang menyenangkan langsung di halaman.

Mengakses kamera secara interaktif

Browser modern dapat memiliki akses langsung ke kamera, sehingga memungkinkan kita membangun pengalaman yang terintegrasi sepenuhnya dengan halaman web dan pengguna tidak akan pernah keluar dari browser.

Mendapatkan akses ke kamera

Kita dapat langsung mengakses kamera menggunakan API dalam spesifikasi WebRTC yang disebut getUserMedia(). getUserMedia() akan meminta akses pengguna ke mikrofon dan kamera yang terhubung.

Jika berhasil, API akan menampilkan Stream yang akan berisi data dari kamera atau mikrofon, lalu kita dapat melampirkannya ke elemen <video>, melampirkannya ke streaming WebRTC, atau menyimpannya menggunakan MediaRecorder API.

Untuk mendapatkan data dari kamera, kita cukup menetapkan video: true di objek batasan yang diteruskan ke 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>

Jika ingin memilih kamera tertentu, Anda dapat menghitung kamera yang tersedia terlebih dahulu.

navigator.mediaDevices.enumerateDevices().then((devices) => {
  devices = devices.filter((d) => d.kind === 'videoinput');
});

Kemudian, Anda dapat meneruskan deviceId yang ingin digunakan saat memanggil getUserMedia.

navigator.mediaDevices.getUserMedia({
  audio: true,
  video: {
    deviceId: devices[0].deviceId,
  },
});

Informasi ini saja tidak terlalu berguna. Yang dapat kami lakukan hanyalah mengambil data video dan memutarnya kembali.

Mengakses data mentah dari kamera

Untuk mengakses data video mentah dari kamera, Anda dapat menggambar setiap frame ke dalam <canvas> dan memanipulasi piksel secara langsung.

Untuk kanvas 2D, Anda dapat menggunakan metode drawImage konteks untuk menggambar frame saat ini dari elemen <video> ke dalam kanvas.

context.drawImage(myVideoElement, 0, 0);

Dengan kanvas WebGL, Anda dapat menggunakan elemen <video> sebagai sumber tekstur.

gl.texImage2D(
  gl.TEXTURE_2D,
  0,
  gl.RGBA,
  gl.RGBA,
  gl.UNSIGNED_BYTE,
  myVideoElement,
);

Perhatikan bahwa dalam kedua kasus, tindakan ini akan menggunakan frame saat ini dari video yang sedang diputar. Untuk memproses beberapa frame, Anda harus menggambar ulang video ke kanvas setiap kali.

Anda dapat mempelajari lebih lanjut hal ini dalam artikel kami tentang menerapkan efek real-time ke gambar dan video.

Menyimpan data dari kamera

Cara termudah untuk menyimpan data dari kamera adalah dengan menggunakan MediaRecorder API.

MediaRecorder API akan mengambil streaming yang dibuat oleh getUserMedia, lalu menyimpan data dari streaming tersebut secara progresif ke tujuan yang Anda inginkan.

<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>

Dalam kasus ini, kita menyimpan data langsung ke dalam array yang nantinya dapat kita ubah menjadi Blob yang kemudian dapat digunakan untuk disimpan ke Server Web kita atau langsung di penyimpanan di perangkat pengguna.

Meminta izin untuk menggunakan kamera secara bertanggung jawab

Jika pengguna sebelumnya belum memberikan akses ke kamera kepada situs Anda, maka saat Anda memanggil getUserMedia, browser akan meminta pengguna untuk memberikan izin ke kamera kepada situs Anda.

Pengguna tidak suka diminta memberikan akses ke perangkat canggih di komputer mereka dan mereka akan sering memblokir permintaan tersebut, atau mengabaikannya jika tidak memahami konteks pembuatan dialog tersebut. Praktik terbaiknya adalah hanya meminta akses ke kamera saat pertama kali diperlukan. Setelah pengguna memberikan akses, mereka tidak akan ditanya lagi. Namun, jika mereka menolak akses, Anda tidak dapat memperoleh akses lagi untuk meminta izin kepada pengguna.

Menggunakan permissions API untuk memeriksa apakah Anda sudah memiliki akses

getUserMedia API tidak memberi tahu Anda apakah Anda sudah memiliki akses ke kamera. Hal ini menimbulkan masalah, yaitu untuk menyediakan UI yang bagus agar pengguna memberi Anda akses ke kamera, Anda harus meminta akses ke kamera.

Hal ini dapat diatasi di beberapa browser dengan menggunakan Permission API. navigator.permission API memungkinkan Anda mengkueri status kemampuan untuk mengakses API tertentu tanpa harus meminta lagi.

Untuk mengkueri apakah Anda memiliki akses ke kamera pengguna, Anda dapat meneruskan {name: 'camera'} ke metode kueri dan metode ini akan menampilkan:

  • granted — pengguna sebelumnya telah memberi Anda akses ke kamera;
  • prompt — pengguna belum memberi Anda akses dan akan diminta saat Anda memanggil getUserMedia;
  • denied — sistem atau pengguna telah secara eksplisit memblokir akses ke kamera dan Anda tidak akan bisa mendapatkan akses ke kamera.

Sekarang, Anda dapat memeriksa dengan cepat apakah Anda perlu mengubah antarmuka pengguna untuk mengakomodasi tindakan yang perlu dilakukan pengguna.

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

Masukan