當前位置:
首頁 > 知識 > 攝像頭操作指南

攝像頭操作指南

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

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


準備工作

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

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

ngrok (https://ngrok.com/) 以便你能通過移動設備輕鬆訪問到你的項目(也因為我覺得 ngrok 炒雞棒)

這個 GitHub 庫 (https://github.com/philnash/mediadevices-camera-selection) 的代碼讓你起步

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

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 http5000

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

網站看起來像這樣:


獲取 media stream

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

// app.js

constvideo=document.getElementById("video");

constbutton=document.getElementById("button");

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

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

button.addEventListener("click",event=>{

constconstraints={

video:true,

audio:false

};

navigator.mediaDevices

.getUserMedia(constraints)

.then(stream=>{

video.srcObject=stream;

})

.catch(error=>{

console.error(error);

});

});

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

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


可用攝像頭

media Devices API 為我們提供了一種枚舉所有可用音頻和視頻輸入設備的方式。我們要用 enumerateDevices 函數來為 框構建選項,這樣我們就能用它來選擇我們想看的攝像頭了。再次打開 app.js,從 DOM 中選出 元素:

constvideo=document.getElementById("video");

constbutton=document.getElementById("button");

constselect=document.getElementById("select");

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

首先要做的是清空 現有的任何選項,然後插入一個空的 。接著循環遍歷所有設備,過濾掉非 「videoinput」類型的設備。然後我們創建一個 元素,用設備 ID 當作 option value,設備 label 當作 option text。我們還要處理一種情況,如果一個設備沒有 label 存在,生成一個簡單的 「Camera n」 作為標籤。

constvideo=document.getElementById("video");

constbutton=document.getElementById("button");

constselect=document.getElementById("select");

functiongotDevices(mediaDevices){

select.innerHTML="";

select.appendChild(document.createElement("option"));

letcount=1;

mediaDevices.forEach(mediaDevice=>{

if(mediaDevice.kind==="videoinput"){

constoption=document.createElement("option");

option.value=mediaDevice.deviceId;

constlabel=mediaDevice.label||`Camera${count++}`;

consttextNode=document.createTextNode(label);

option.appendChild(textNode);

select.appendChild(option);

}

});

}

在 app.js 末尾調用一下 enumerateDevices。

navigator.mediaDevices.enumerateDevices().then(gotDevices);

刷新頁面,看一下按鈕旁邊的下拉選擇框。如果你用的是 Android ,或者使用 Chrome 或 Firefox,你就能看到可用的攝像頭名稱了。

然而在 iPhone 上,你將看到我們函數生成的通用名字 「Camera 1」 和 「Camera 2」。在 iOS 上只有你授權至少一個攝像頭給網站,你才能看到攝像頭的名字。這讓在我們的界面上選擇攝像頭變得更不方便,因為儘管你能獲取到設備 ID,你還是不能分辨哪個攝像頭是哪個。

目前我們還沒有處理下拉選擇框來改變攝像頭。在這之前,讓我們來看另一種能改變哪個攝像頭被使用的方法。


FacingMode

FacingMode (https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/facingMode) 約束是一個可以用來選擇攝像頭的替代方法。這個方法比起通過 enumerateDevices 函數獲取 ID 來說更不那麼精確,但在移動設備上效果非常好。對於這個約束,一共有四種選項可供你選擇:用戶(user),環境(environment),左(left),右(right)。MDN 上的文檔對這個約束做了詳細介紹, 以本文的目的我們將使用用戶和環境模式,在移動設備上它們正好對應到前置和後置攝像頭。

要使用 facingMode 約束我們需要修改調用 getUserMedia 時使用的 constraints 對象。對於 video 我們需要一個對象來控制具體的約束,而不是給一個 true 值。像這樣修改代碼來使用前置攝像頭:

button.addEventListener("click",event=>{

constvideoConstraints={

facingMode:"user"

};

constconstraints={

video:videoConstraints,

audio:false

};

現在可以用你的手機測試。你應該能看到前置攝像頭被使用。更改 facingMode 為 environment 再試一次, 使用的應該是後置攝像頭。讓我們把這些代碼和上面通過 enumerateDevices 獲取到的結果放到一塊兒,只要我們獲得了讀取攝像頭數據的許可權,就能構建一個攝像頭切換器了。


切換攝像頭

現在我們有在首次選擇時挑選用戶或環境攝像頭的代碼了,但如果我們要切換攝像頭那還有一丟丟額外的工作要做。

首先,我們應該保留對當前流的引用,這樣當我們切換到另一個流時就能停止當前流。在 app.js 的最前面添加一個額外的變數和輔助函數來停止流中的軌。

constvideo=document.getElementById("video");

constbutton=document.getElementById("button");

constselect=document.getElementById("select");

letcurrentStream;

functionstopMediaTracks(stream){

stream.getTracks().forEach(track=>{

track.stop();

});

}

函數 stopMediaTracks 接收一個媒體流,循環遍歷流中的每一個媒體軌道,調用 stop 方法停止媒體軌。

我們要在點擊同一個按鈕時改變攝像頭,所以我們需要更新一下按鈕的事件監聽器了。如果當前有媒體流,我們應該先停止掉它。然後我們要檢查 元素看是否選擇了特定的設備,然後基於此構造 media constraints 對象。

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

button.addEventListener("click",event=>{

if(typeofcurrentStream!=="undefined"){

stopMediaTracks(currentStream);

}

constvideoConstraints={};

if(select.value===""){

videoConstraints.facingMode="environment";

}else{

videoConstraints.deviceId={exact:select.value};

}

constconstraints={

video:videoConstraints,

audio:false

};

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

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

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

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

button.addEventListener("click",event=>{

if(typeofcurrentStream!=="undefined"){

stopMediaTracks(currentStream);

}

constvideoConstraints={};

if(select.value===""){

videoConstraints.facingMode="environment";

}else{

videoConstraints.deviceId={exact:select.value};

}

constconstraints={

video:videoConstraints,

audio:false

};

navigator.mediaDevices

.getUserMedia(constraints)

.then(stream=>{

currentStream=stream;

video.srcObject=stream;

returnnavigator.mediaDevices.enumerateDevices();

})

.then(gotDevices)

.catch(error=>{

console.error(error);

});

});

當你添加完所有的代碼,你的 app.js 應該看起來像這個文件 (https://github.com/philnash/mediadevices-camera-selection/blob/master/app.js) 一樣。刷新頁面然後你就能愉快地選擇和改變攝像頭了。這個頁面在移動設備和電腦上都有效。


下一步

我們已經看到如何通過使用 facingMode 和 deviceId 約束來選擇用戶的攝像頭。記住,在你有許可權使用攝像頭之前,facingMode 更可靠,但是選擇 deviceId 更加精確。你可以從 GitHub 倉庫 (https://github.com/philnash/mediadevices-camera-selection) 中得到所有本文中的代碼,你也可以從這裡嘗試在線版的應用 (https://philnash.github.io/mediadevices-camera-selection/)。

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

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

還有哪些其他你想看到的在視頻聊天中有用的功能?或者對這個功能有什麼疑問?歡迎在評論中留言或者在 Twitter 上 @philnash。

英文:Phil Nash 譯文:眾成翻譯/Will Liu

www.zcfy.cc/article/choosing-cameras-in-javascript-with-the-mediadevices-api


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 JavaScript 的精彩文章:

35歲以後的程序員都沒活幹了?
Node.js 10.0.0 正式發布,帶來大量改進和修復

TAG:JavaScript |