Thứ tư, 27/05/2020 | 00:00 GMT+7

Cách truy cập camera trước và sau bằng JavaScript's getUserMedia ()

Với HTML5, sự ra đời của các API có quyền truy cập vào phần cứng của thiết bị, bao gồm cả API MediaDevices . API này cung cấp quyền truy cập vào các thiết bị đầu vào đa phương tiện như âm thanh và video.

Với sự trợ giúp của API này, các nhà phát triển có thể truy cập các thiết bị âm thanh và video để phát và hiển thị nguồn cấp dữ liệu video trực tiếp trong trình duyệt. Trong hướng dẫn này, bạn sẽ truy cập nguồn cấp dữ liệu video từ thiết bị của user và hiển thị nó trong trình duyệt bằng phương pháp getUserMedia .

API getUserMedia sử dụng các thiết bị đầu vào đa phương tiện để tạo MediaStream . MediaStream này chứa các loại phương tiện được yêu cầu, cho dù là âm thanh hay video. Sử dụng stream trả về từ API, nguồn cấp dữ liệu video có thể được hiển thị trên trình duyệt, điều này rất hữu ích cho giao tiếp thời gian thực trên trình duyệt.

Khi được sử dụng cùng với API ghi MediaStream , bạn có thể ghi và lưu trữ dữ liệu phương tiện được ghi lại trên trình duyệt. API này chỉ hoạt động trên các nguồn root an toàn giống như phần còn lại của các API mới được giới thiệu, nhưng nó cũng hoạt động trên server localhost và URL file .

Yêu cầu

Hướng dẫn này trước tiên sẽ giải thích các khái niệm và minh họa các ví dụ với Codepen . Trong bước cuối cùng, bạn sẽ tạo một nguồn cấp dữ liệu video đang hoạt động cho trình duyệt.

Bước 1 - Kiểm tra hỗ trợ thiết bị

Đầu tiên, bạn sẽ thấy cách kiểm tra xem trình duyệt của user có hỗ trợ API mediaDevices . API này tồn tại trong giao diện trình chuyển và chứa trạng thái hiện tại và danh tính của tác nhân user . Việc kiểm tra được thực hiện với đoạn mã sau có thể được paste vào Codepen:

if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) {   console.log("Let's get this party started") } 

Đầu tiên, điều này sẽ kiểm tra xem API mediaDevices có tồn tại trong trình navigator hay không và sau đó kiểm tra xem API getUserMedia có sẵn trong mediaDevices . Nếu điều này trả về true , bạn có thể bắt đầu.

Bước 2 - Yêu cầu quyền của user

Sau khi xác nhận sự hỗ trợ của trình duyệt cho getUserMedia , bạn cần yêu cầu quyền sử dụng các thiết bị đầu vào phương tiện trên tác nhân user . Thông thường, sau khi user cấp quyền, một Promise sẽ được trả lại sẽ phân giải thành stream phương tiện. Promise này sẽ không được trả lại khi user từ chối quyền, điều này sẽ chặn quyền truy cập vào các thiết bị này.

Dán dòng sau vào Codepen để yêu cầu quyền:

navigator.mediaDevices.getUserMedia({video: true}) 

Đối tượng được cung cấp làm đối số cho phương thức getUserMedia được gọi là các constraints . Điều này xác định thiết bị đầu vào phương tiện nào bạn đang yêu cầu quyền truy cập. Ví dụ: nếu đối tượng chứa audio: true , user sẽ được yêu cầu cấp quyền truy cập vào thiết bị đầu vào âm thanh.

Bước 3 - Hiểu các ràng buộc về phương tiện

Phần này sẽ bao gồm các khái niệm chung của contraints . Đối tượng constraints là một đối tượng MediaStreamConstraints chỉ định các loại phương tiện cần yêu cầu và các yêu cầu của từng loại phương tiện. Bạn có thể chỉ định các yêu cầu cho stream được yêu cầu bằng cách sử dụng đối tượng constraints , như độ phân giải của stream sẽ sử dụng ( front , back ).

Bạn phải chỉ định audio hoặc video khi đưa ra yêu cầu. NotFoundError sẽ được trả lại nếu không tìm thấy loại phương tiện được yêu cầu trên trình duyệt của user .

Nếu bạn định yêu cầu một stream video có độ phân giải 1280 x 720 , bạn có thể cập nhật đối tượng constraints để trông giống như sau:

{   video: {     width: 1280,     height: 720,   } } 

Với bản cập nhật này, trình duyệt sẽ cố gắng trùng với cài đặt chất lượng được chỉ định cho stream . Nếu thiết bị video không thể cung cấp độ phân giải này, trình duyệt sẽ trả về các độ phân giải khả dụng khác.

Để đảm bảo trình duyệt trả về độ phân giải không thấp hơn độ phân giải được cung cấp, bạn sẽ phải sử dụng thuộc tính min . Đây là cách bạn có thể cập nhật đối tượng constraints để bao gồm thuộc tính min :

{   video: {     width: {       min: 1280,     },     height: {       min: 720,     }   } } 

Điều này sẽ đảm bảo độ phân giải stream được trả về tối thiểu là 1280 x 720 . Nếu không thể đáp ứng yêu cầu tối thiểu này, lời hứa sẽ bị từ chối và báo lỗi OverconstrainedError .

Trong một số trường hợp, bạn có thể lo lắng về việc lưu dữ liệu và cần stream không vượt quá độ phân giải đã đặt. Điều này có thể hữu ích khi user sử dụng gói giới hạn. Để bật chức năng này, hãy cập nhật đối tượng ràng buộc để chứa trường max :

{   video: {     width: {       min: 1280,       max: 1920,     },     height: {       min: 720,       max: 1080     }   } } 

Với các cài đặt này, trình duyệt sẽ đảm bảo stream trả về không dưới 1280 x 720 và không vượt quá 1920 x 1080 .

Các thuật ngữ khác được dùng bao gồm exactideal . Cài đặt ideal thường được sử dụng cùng với các thuộc tính max minmax để tìm cài đặt tốt nhất có thể gần nhất với các giá trị lý tưởng được cung cấp.

Bạn có thể cập nhật các ràng buộc để sử dụng từ khóa ideal :

{   video: {     width: {       min: 1280,       ideal: 1920,       max: 2560,     },     height: {       min: 720,       ideal: 1080,       max: 1440     }   } } 

Để yêu cầu trình duyệt sử dụng camera trước hoặc sau (trên thiết bị di động) trên thiết bị, bạn có thể chỉ định facingMode tính facingMode trong đối tượng video :

{   video: {     width: {       min: 1280,       ideal: 1920,       max: 2560,     },     height: {       min: 720,       ideal: 1080,       max: 1440     },     facingMode: 'user'   } } 

Cài đặt này sẽ sử dụng máy ảnh mặt trước mọi lúc trên mọi thiết bị. Để sử dụng camera sau trên thiết bị di động, bạn có thể thay đổi thuộc tính facingMode theo environment .

{   video: {     ...     facingMode: {       exact: 'environment'     }   } } 

Bước 4 - Sử dụng phương pháp enumerateDevices

Khi phương thức enumerateDevices được gọi, nó trả về tất cả các thiết bị phương tiện đầu vào có sẵn trên PC của user .

Với phương pháp này, bạn có thể cung cấp các tùy chọn user mà thiết bị phương tiện đầu vào sẽ sử dụng để phát trực tuyến nội dung âm thanh hoặc video. Phương thức này trả về một Promise được phân giải thành mảng MediaDeviceInfo chứa thông tin về từng thiết bị.

Ví dụ về cách sử dụng phương pháp này được hiển thị trong đoạn mã dưới đây:

async function getDevices() {   const devices = await navigator.mediaDevices.enumerateDevices(); } 

Một phản hồi mẫu cho mỗi thiết bị sẽ giống như sau:

{   deviceId: "23e77f76e308d9b56cad920fe36883f30239491b8952ae36603c650fd5d8fbgj",   groupId: "e0be8445bd846722962662d91c9eb04ia624aa42c2ca7c8e876187d1db3a3875",   kind: "audiooutput",   label: "", } 

Lưu ý: Nhãn sẽ không được trả lại trừ khi có một stream sẵn có hoặc nếu user đã cấp quyền truy cập thiết bị.

Bước 5 - Hiển thị Luồng Video trên Trình duyệt

Bạn đã trải qua quá trình yêu cầu và nhận quyền truy cập vào các thiết bị đa phương tiện, cấu hình các ràng buộc để bao gồm các độ phân giải cần thiết và chọn máy ảnh bạn cần để quay video.

Sau khi thực hiện tất cả các bước này, ít nhất bạn cần xem liệu stream có đang phân phối hay không dựa trên cài đặt đã cấu hình . Để đảm bảo điều này, bạn sẽ sử dụng phần tử <video> để hiển thị stream video trên trình duyệt.

Giống như đã đề cập trước đó, phương thức getUserMedia trả về một Promise có thể được phân giải thành một stream . Luồng trả về có thể được chuyển đổi thành URL đối tượng bằng phương thức createObjectURL . URL này sẽ được đặt làm nguồn video.

Bạn sẽ tạo một bản demo ngắn trong đó ta cho phép user chọn từ danh sách thiết bị video có sẵn của họ. bằng phương thức enumerateDevices .

Đây là một phương thức navigator.mediaDevices . Nó liệt kê các thiết bị media khả dụng, chẳng hạn như micrô và máy ảnh. Nó trả về một Promise thể phân giải được cho một mảng các đối tượng nêu chi tiết các thiết bị phương tiện có sẵn.

Tạo index.html và cập nhật nội dung bằng mã bên dưới:

index.html
<!doctype html> <html lang="en"> <head>     <meta charset="UTF-8">     <meta name="viewport"           content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">     <meta http-equiv="X-UA-Compatible" content="ie=edge">     <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">     <link rel="stylesheet" href="style.css">     <title>Document</title> </head> <body> <div class="display-cover">     <video autoplay></video>     <canvas class="d-none"></canvas>      <div class="video-options">         <select name="" id="" class="custom-select">             <option value="">Select camera</option>         </select>     </div>      <img class="screenshot-image d-none" alt="">      <div class="controls">         <button class="btn btn-danger play" title="Play"><i data-feather="play-circle"></i></button>         <button class="btn btn-info pause d-none" title="Pause"><i data-feather="pause"></i></button>         <button class="btn btn-outline-success screenshot d-none" title="ScreenShot"><i data-feather="image"></i></button>     </div> </div>  <script src="https://unpkg.com/feather-icons"></script> <script src="script.js"></script> </body> </html> 

Trong đoạn mã trên, bạn đã cài đặt các yếu tố bạn cần và một vài điều khiển cho video. Ngoài ra còn có một nút để chụp ảnh màn hình của nguồn cấp video hiện tại.

Bây giờ, hãy tạo kiểu cho các thành phần này một chút.

Tạo style.css và sao chép các kiểu sau vào đó. Bootstrap được đưa vào để giảm số lượng CSS bạn cần viết để các thành phần hoạt động.

style.css
.screenshot-image {     width: 150px;     height: 90px;     border-radius: 4px;     border: 2px solid whitesmoke;     box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.1);     position: absolute;     bottom: 5px;     left: 10px;     background: white; }  .display-cover {     display: flex;     justify-content: center;     align-items: center;     width: 70%;     margin: 5% auto;     position: relative; }  video {     width: 100%;     background: rgba(0, 0, 0, 0.2); }  .video-options {     position: absolute;     left: 20px;     top: 30px; }  .controls {     position: absolute;     right: 20px;     top: 20px;     display: flex; }  .controls > button {     width: 45px;     height: 45px;     text-align: center;     border-radius: 100%;     margin: 0 6px;     background: transparent; }  .controls > button:hover svg {     color: white !important; }  @media (min-width: 300px) and (max-width: 400px) {     .controls {         flex-direction: column;     }      .controls button {         margin: 5px 0 !important;     } }  .controls > button > svg {     height: 20px;     width: 18px;     text-align: center;     margin: 0 auto;     padding: 0; }  .controls button:nth-child(1) {     border: 2px solid #D2002E; }  .controls button:nth-child(1) svg {     color: #D2002E; }  .controls button:nth-child(2) {     border: 2px solid #008496; }  .controls button:nth-child(2) svg {     color: #008496; }  .controls button:nth-child(3) {     border: 2px solid #00B541; }  .controls button:nth-child(3) svg {     color: #00B541; }  .controls > button {     width: 45px;     height: 45px;     text-align: center;     border-radius: 100%;     margin: 0 6px;     background: transparent; }  .controls > button:hover svg {     color: white; } 

Bước tiếp theo là thêm chức năng vào bản demo. Sử dụng phương thức enumerateDevices , bạn sẽ nhận được các thiết bị video có sẵn và đặt nó làm tùy chọn trong phần tử được chọn. Tạo một file có tên script.js và cập nhật nó bằng đoạn mã sau:

script.js
feather.replace();  const controls = document.querySelector('.controls'); const cameraOptions = document.querySelector('.video-options>select'); const video = document.querySelector('video'); const canvas = document.querySelector('canvas'); const screenshotImage = document.querySelector('img'); const buttons = [...controls.querySelectorAll('button')]; let streamStarted = false;  const [play, pause, screenshot] = buttons;  const constraints = {   video: {     width: {       min: 1280,       ideal: 1920,       max: 2560,     },     height: {       min: 720,       ideal: 1080,       max: 1440     },   } };  const getCameraSelection = async () => {   const devices = await navigator.mediaDevices.enumerateDevices();   const videoDevices = devices.filter(device => device.kind === 'videoinput');   const options = videoDevices.map(videoDevice => {     return `<option value="${videoDevice.deviceId}">${videoDevice.label}</option>`;   });   cameraOptions.innerHTML = options.join(''); };  play.onclick = () => {   if (streamStarted) {     video.play();     play.classList.add('d-none');     pause.classList.remove('d-none');     return;   }   if ('mediaDevices' in navigator && navigator.mediaDevices.getUserMedia) {     const updatedConstraints = {       ...constraints,       deviceId: {         exact: cameraOptions.value       }     };     startStream(updatedConstraints);   } };  const startStream = async (constraints) => {   const stream = await navigator.mediaDevices.getUserMedia(constraints);   handleStream(stream); };  const handleStream = (stream) => {   video.srcObject = stream;   play.classList.add('d-none');   pause.classList.remove('d-none');   screenshot.classList.remove('d-none');   streamStarted = true; };  getCameraSelection(); 

Trong đoạn mã trên, có một số điều đang diễn ra. Hãy chia nhỏ chúng:

  1. feather.replace() : phương thức này gọi khởi tạo lông , là một biểu tượng được cài đặt để phát triển web.
  2. Biến constraints giữ cấu hình ban đầu cho stream . Điều này sẽ được mở rộng để bao gồm thiết bị phương tiện mà user chọn.
  3. getCameraSelection : hàm này gọi phương thức enumerateDevices . Sau đó, bạn lọc qua mảng từ Promise giải và chọn thiết bị đầu vào video. Từ kết quả đã lọc, bạn tạo <option> cho phần tử <select> .
  4. Việc gọi phương thức getUserMedia xảy ra trong trình nghe onclick của nút play . Tại đây, bạn sẽ kiểm tra xem phương pháp này có được trình duyệt của user hỗ trợ hay không trước khi bắt đầu stream .
  5. Tiếp theo, bạn sẽ gọi hàm startStream có đối số constraints . Nó gọi phương thức getUserMedia với các constraints được cung cấp. handleStream được gọi bằng cách sử dụng stream từ Promise giải. Phương thức này đặt stream trả về thành srcObject của phần tử video.

Tiếp theo, bạn sẽ thêm trình nghe nhấp chuột vào các node điều khiển trên trang để pause , stopscreenshots . Ngoài ra, bạn sẽ thêm một trình nghe vào phần tử <select> để cập nhật các ràng buộc stream với thiết bị video đã chọn.

Cập nhật file script.js với mã bên dưới:

script.js
... cameraOptions.onchange = () => {   const updatedConstraints = {     ...constraints,     deviceId: {       exact: cameraOptions.value     }   };   startStream(updatedConstraints); };  const pauseStream = () => {   video.pause();   play.classList.remove('d-none');   pause.classList.add('d-none'); };  const doScreenshot = () => {   canvas.width = video.videoWidth;   canvas.height = video.videoHeight;   canvas.getContext('2d').drawImage(video, 0, 0);   screenshotImage.src = canvas.toDataURL('image/webp');   screenshotImage.classList.remove('d-none'); };  pause.onclick = pauseStream; screenshot.onclick = doScreenshot; 

Bây giờ, khi bạn mở index.html trong trình duyệt, nhấp vào nút Phát sẽ bắt đầu stream .

Đây là một bản demo hoàn chỉnh:

https://codepen.io/chrisbeast/pen/ebYwpX

Kết luận

Hướng dẫn này đã giới thiệu API getUserMedia . Đây là một bổ sung thú vị cho HTML5 giúp giảm bớt quá trình thu thập phương tiện trên web.

API nhận một tham số ( constraints ) được dùng để cấu hình quyền truy cập vào các thiết bị đầu vào âm thanh và video. Nó cũng được dùng để chỉ định độ phân giải video cần thiết cho ứng dụng của bạn.

Bạn có thể mở rộng bản demo hơn nữa để cung cấp cho user tùy chọn lưu ảnh chụp màn hình đã chụp, cũng như ghi và lưu trữ dữ liệu video và âm thanh với sự trợ giúp của MediaStream Recording API.


Tags:

Các tin liên quan