1. 程式人生 > 其它 >使用基於 WebRTC 的 JavaScript API 在瀏覽器環境裡呼叫本機攝像頭

使用基於 WebRTC 的 JavaScript API 在瀏覽器環境裡呼叫本機攝像頭

HTML5,JavaScript 和現代瀏覽器這套三駕馬車的組合,使得傳統的 Web 應用較之過去能實現更多更豐富的同用戶互動的功能。攝像頭如今已成為智慧手機的標配,前端 Web 應用也出現了越來越多的開啟本機攝像頭,掃描條形碼,二維碼等需求。

本文介紹兩種通過 JavaScript 實現在瀏覽器環境裡呼叫裝置攝像頭的開發技術。

方法1:基於現代瀏覽器支援的 WebRTC API 實現

我採用該思路實現了一個簡單的 Web 頁面,全部原始碼維護在如下的 Github 程式碼倉庫裡:

https://github.com/wangzixi-diablo/WebAppCollection/tree/main/WebContent/camera

首先看看執行該 Web 應用的效果。

通過膝上型電腦訪問,瀏覽器會彈出視窗詢問使用者是否允許該應用訪問裝置上的攝像頭:

點選允許之後,應用下方區域就會實時顯示我的攝像頭正對著的區域的影象:

點選“拍照”按鈕後,攝像頭顯示的影象就會被固化在該按鈕下方,並且以圖片的方式自動儲存到本地。

在我的三星手機上訪問該連結,首先一樣要授權該應用使用攝像頭:

對準我電腦面前一個異形手辦進行拍照:

自動生成一張圖片並儲存到手機上:

幾個關鍵的實現點說明:

(1) JavaScript 之所以通過瀏覽器能夠識別到裝置可用攝像頭(包括可用的音訊輸入和輸出裝置),是因為現代瀏覽器支援的一組名為 WebRTC(Web Real Time Communication,網頁即時通訊)的 API. 這個 API 能幫助 Web 應用開發人員通過簡單的 JavaScript 程式設計就能實現功能豐富的實時多媒體應用,而無需學習多媒體的數字訊號處理知識。Web 應用的使用者也無需下載額外的外掛。

用 JavaScript 進行裝置可用多媒體裝置的檢測,核心程式碼如下:

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

這句程式碼前半段 navigator.mediaDevices.enumerateDevices() 是瀏覽器支援的原生 API,這是一個非同步呼叫,返回一個 promise 物件:

等到該非同步呼叫的結果可供應用程式使用之後,我們通過鏈式呼叫 then 傳入的回撥函式 gotDevices 被觸發,輸入的引數就是 navigator.mediaDevices.enumerateDevices() 呼叫的返回值。在偵錯程式裡看看這個返回值的明細:

從偵錯程式裡得知 enumerateDevices 這個函式返回了我膝上型電腦上一系列可用的音視訊裝置,這些資訊和我通過作業系統裡看到的裝置資訊一致:

(2) 我的 html 頁面裡定義了一個 HTML5 原生支援的 video 標籤, 用於顯示通過裝置攝像頭觀察到的影象。

但是我們還需要把裝置攝像頭同這個 video 標籤關聯起來。方式是給這個標籤的 dom 物件的srcObject 屬性賦一個 MediaStream (媒體資料流)物件。

這個 MediaStream 物件從哪裡來?同理,通過鏈式呼叫navigator.mediaDevices.getUserMedia(constraints) 得到:

(3) 點選拍照按鈕後,自動生成圖片並下載到本地的功能在按鈕的 click 事件響應函式裡實現。首先呼叫 canvas 標籤對應 Context 的 API drawImage 將顯示攝像頭內容的 video 標籤當前顯示的內容繪製到 canvas 標籤頁上,然後用此內容生成格式為 jpeg 的圖片,下載到本地。

方法2:使用 SAP UI5 自定義控制元件

這種方式本質上同方法一異曲同工,只不是封裝性更好,將方法1 描述的步驟,封裝成一個 SAP UI5 可重用控制元件,方便使用 SAP UI5 這個前端框架進行開發的前端程式設計師直接使用。

關於 SAP UI5 這個企業級前端開發框架的介紹,參考筆者之前的 InfoQ 文章:面向企業級前端應用的開發框架 UI5 的發展簡史介紹。

先回憶方法1 技術實現的要點:

(1) 在 web 應用的 HTML 頁面裡定義 HTML5 用於顯示視訊的原生標籤: video

(2) 使用 WebRTC 的 API,獲取裝置攝像頭對應的 MediaStream 物件,再將這個物件例項賦給 video 標籤對應的 DOM物件的 srcObject 屬性.

以上兩步實現之後,我們通過攝像頭觀察到的視訊影象,就能實時顯示在 web 應用的 video 標籤裡了。至於將某一時間點裡 video 標籤裡顯示的視訊內容儲存成圖片並下載,其對應的 JavaScript 程式碼對於所有的前端框架並沒有太大的不同,本文略過。

因此,使用 SAP UI5 開發,我們無非得重複以上兩個步驟。

SAP UI5 應用最常用的檢視格式為 XML 檢視。我們直接在 XML 視圖裡加上 HTML 原生的 video 或者 div 標籤,會發生什麼?

404 錯誤,UI5 框架載入不了 div.js 這個指令碼檔案。

筆者以前還在 SAP 成都研究院 CRM Fiori 應用開發團隊工作時,曾經寫過一個 SAP UI5 框架程式碼的學習教程,裡面有兩篇文章,詳細介紹了 SAP UI5 XML 檢視執行時的渲染原理:

  1. Why my formatter does not work? A trouble shooting example to know how it works
  2. How I do self-study on a given Fiori control – part 10

簡單地說,就是 SAP UI5 裡有個 XMLTemplateProcessor.js 的實現,執行時當 XML 檢視的原始檔被瀏覽器載入解析成 DOM 後,它會對 DOM 樹進行深度優先遍歷,對遇到的每一個 UI5 標籤,載入其實現檔案(如果是在 UI5 除錯模式下),然後建立這個標籤對應的例項。

回到本文的例子,我寫到 SAP UI5 XML 視圖裡的 div 標籤被當成了一個 SAP UI5 XML 的控制元件,所以 UI5 框架自動去找這個根本不存在的 div 控制元件的實現檔案,當然找不到了。

知道問題出在哪裡,解決的思路自然就有了。自己把 HTML5 原生標籤 video 封裝成 UI5 控制元件不就行了?

SAP UI5 開源社群裡已經有一個封裝好的 library:

https://github.com/tiagobalmeida/openui5-camera

先看這個例子在膝上型電腦上訪問的效果:

點選頁面上顯示的攝像頭拍攝的內容,能自動儲存成一張圖片。
手機上的顯示效果:

然後再來看這個 library 的實現原理。

這個 camera 自定義 UI5 控制元件實現的層級結果如下:

SAP UI5 自定義控制元件的實現包括三個 JavaScript 檔案:

  • library.js:定義這個控制元件抬頭級別的控制資訊,比如名稱,版本號,依賴等。

  • Camera.js:實現了將 WebRTC API 獲得的 MediaStream 物件例項繫結到控制元件封裝的 video 元素上的步驟。

  • CameraRender.js:負責將這個自定義控制元件在XML視圖裡的標籤 Camera 渲染成原生的video和canvas標籤的組合。

SAP UI5 的每一個控制元件都有一個與之對應的渲染類,用於完成 XML 視圖裡 UI5 的標籤到 HTML5 原生標籤的轉換:

如何使用這個自定義控制元件呢?

在 XML 視圖裡使用如下定義即可:

<cam:Camera
    id="idCamera"
    width="800"
    height="600"
    snapshot=".onSnapshot" />

總結

本文介紹了基於 WebRTC 技術使用 JavaScript 呼叫本機攝像頭的解決方案。WebRTC 可以為基於開放標準的應用程式新增實時通訊功能,支援在對等點之間傳送視訊、語音和通用資料,允許開發人員構建強大的語音和視訊通訊解決方案。

WebRTC 可用於所有現代瀏覽器以及所有主流作業系統的本地客戶端。WebRTC 背後的技術是作為一個開放的 Web 標準實現,並且可以在所有主流瀏覽器中作為常規 JavaScript API 使用。

本文兩個例子在 Windows 10 作業系統的 Chrome 瀏覽器裡實現並通過測試。對於原生客戶端,如 Android 和 iOS 應用程式,可以使用提供相同功能的 WebRTC 庫。

希望本文介紹的知識點對大家採取 JavaScript 實現瀏覽器環境裡呼叫本機攝像頭的需求能有所幫助,感謝閱讀。