JavaScript 使用 mediaDevices API 選擇攝像頭


大多數智能手機都有前置和后置攝像頭,當你在創建視頻應用時你可能想要選擇或者切換前置、后置攝像頭。

如果你開發的是一款聊天應用,你很可能會想調用前置攝像頭,但如果你開發的是一款拍照軟件,那么你會更傾向於使用后置攝像頭。在這篇文章中我們將探討如何通過 mediaDevices API 和 media constraints (媒體約束) 選擇或者切換攝像頭。

准備工作

要跟着本文一起動手實踐你需要:

  • 一款擁有兩個可供測試的攝像頭的 iOS 或 Android 設備,如果你的電腦有兩個攝像頭那也可以

  • ngrok 以便你能通過移動設備輕松訪問到你的項目(也因為我覺得 ngrok 炒雞棒)

  • 這個 GitHub 庫 的代碼讓你起步

要獲取代碼,先把這個項目 clone 下來然后 checkout 到 initial-project tag 下。

git clone https://github.com/philnash/mediadevices-camera-selection.git -b initial-project

cd mediadevices-camera-selection

這個起步項目已經為你准備好了一些 HTML 和 CSS,所以我們就可以把注意集中到 JavaScript 上了。你可以直接打開 index.html,但我建議你用一款 webserver 把這些文件托管起來。我喜歡用 npm 的 serve 模塊。我在這個庫里已經引入了 serve,要使用它你需要先用 npm 安裝依賴然后啟動這個服務。

npm install

npm start

服務運行起來后,我們要用 ngrok 開啟一條隧道。serve 用 5000 端口托管文件,要用 ngrok 開隧道通到這個端口,新開一個命令行窗口輸入以下命令:

`ngrok http 5000`

好了你現在可以公網訪問這個站點了,你可以在移動設備上打開這個網站,這樣接下來就可以測試啦。確保你打開的是 HTTPS 的 URL,因為我們用的 API 只能在安全環境下使用。

網站看起來像這樣:

獲取 media stream

我們的第一個任務是從任意攝像頭獲取視頻流顯示到屏幕上。完成這個之后我們再調研如何選擇特定攝像頭。打開 app.js , 我們以從 DOM 中選擇按鈕和 video 元素開始:

// app.js

const video = document.getElementById('video');

const button = document.getElementById('button');

當用戶點擊或觸摸按鈕時,我們要使用 mediaDevices API 請求攝像頭權限。要這樣做,我們要調用 navigator.mediaDevices.getUserMedia ,傳遞 media constraints 對象。讓我們從簡單的 constraints 開始,我們只需要視頻,因此我們把 video 設置為 true,audio 設置為 false。

getUserMedia 會返回一個 promise,當 resolve 的時候我們就可以訪問到攝像頭的媒體流了。把媒體流賦值給 video 元素的 srcObj 屬性,我們就能從屏幕上看到視頻了。

button.addEventListener('click', event ={

  const constraints {

    videotrue,

    audiofalse

  };

  navigator.mediaDevices

    .getUserMedia(constraints)

    .then(stream ={

      video.srcObject = stream;

    })

    .catch(error ={

      console.error(error);

    });

});

保存文件,重新加載頁面然后點擊按鈕。你應該能看到一個權限對話框請求訪問你的攝像頭,一旦授權屏幕上就應該會出現視頻。在你的電腦和手機上試一試,我在我的 iPhone 上試了,被選擇的是前置攝像頭。

如果你用的是一部 iPhone 手機,確認你在 Safari 里嘗試,因為其他瀏覽器貌似並沒有效果。

可用攝像頭

media Devices API 為我們提供了一種枚舉所有可用音頻和視頻輸入設備的方式。我們要用 enumerateDevices 函數來為元素:

const video = document.getElementById('video');

const button = document.getElementById('button');

const select = document.getElementById('select');

enumerateDevices 會返回一個 promise,所以讓我們寫一個用來接受 promise 結果的函數吧。這個函數接收一個 media device 數組作為參數。

首先要做的是清空元素看是否選擇了特定的設備,然后基於此構造 media constraints 對象。

這樣修改按鈕的點擊處理函數和 video constraints:

button.addEventListener('click', event ={

  if (typeof currentStream !== 'undefined'{

    stopMediaTracks(currentStream);

  }

  const videoConstraints {};

  if (select.value === ''{

    videoConstraints.facingMode 'environment';

  else {

    videoConstraints.deviceId { exact: select.value };

  }

  const constraints {

    video: videoConstraints,

    audiofalse

  };

當我們想通過 deviceId 來選擇設備時,使用 exact 約束。 可是對於 facingMode,我們沒有使用 exact 約束, 否則在一個無法識別有沒有用戶或環境模式的設備上將會失敗,導致我們什么媒體設備也拿不到。

當我們獲得使用視頻的權限時,在點擊處理函數內,我們還要修改一些別的東西。把傳遞給函數的新流賦值給 currentStream 以便后續調用 stop,觸發另一次 enumerateDevices 的調用。

enumerateDevices 返回一個 promise,所以在我們的 then 函數中可以直接返回它,然后鏈式創建一個新的 then 把結果傳遞給 gotDevices 函數處理。

用以下代碼替換現有的 getUserMedia 調用:

button.addEventListener('click', event ={

  if (typeof currentStream !== 'undefined'{

    stopMediaTracks(currentStream);

  }

  const videoConstraints {};

  if (select.value === ''{

    videoConstraints.facingMode 'environment';

  else {

    videoConstraints.deviceId { exact: select.value };

  }

  const constraints {

    video: videoConstraints,

    audiofalse

  };

 

  navigator.mediaDevices

    .getUserMedia(constraints)

    .then(stream ={

      currentStream = stream;

      video.srcObject = stream;

      return navigator.mediaDevices.enumerateDevices();

    })

    .then(gotDevices)

    .catch(error ={

      console.error(error);

    });

});

當你添加完所有的代碼,你的 app.js 應該看起來像這個文件一樣。刷新頁面然后你就能愉快地選擇和改變攝像頭了。這個頁面在移動設備和電腦上都有效。

下一步

我們已經看到如何通過使用 facingMode 和 deviceId 約束來選擇用戶的攝像頭。記住,在你有權限使用攝像頭之前,facingMode 更可靠,但是選擇 deviceId 更加精確。你可以從 GitHub 倉庫 中得到所有本文中的代碼,你也可以從這里嘗試在線版的應用。

如果你正在使用 Twilio Video 構建視頻應用,你可以在調用 connect 或者 createLocalVideoTrack的時候使用這些 constraints。

對於視頻聊天來說,選擇和切換攝像頭是非常有用的功能,允許用戶在你的應用界面准確地選擇他們想用的攝像頭,並且還能做到在視頻通話時分享你的屏幕。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM