1. 程式人生 > >瀏覽器中打開攝像頭

瀏覽器中打開攝像頭

then lec ref 成功 video 第一個 對象 defined mac os x

  本文是講述如何在瀏覽器中打開攝像頭,並且實時顯示在頁面上。想要實現這一功能,需要依賴WebRTC (Web Real-Time Communications) 這一實時通訊技術,它允許瀏覽器之間視頻流和音頻流或者其他任意數據的傳輸,當然其中包含了大量的API和協議,這些在這裏都不做介紹,具體的標準還在完善之中,所以使用的方法有時候也需要考慮到兼容問題,那麽回到主題,怎樣使用webRTC獲取視頻流。

  首先對於html,我們需要一個video標簽來播放視頻(JS中添加也可以),當然畫布也是能夠實現的。使用video有些屬性必須要配置。

<video id="video" autoplay playsinline
></video>

  上面兩個屬性必須要添加,autoplay設置video自動播放,否則通信成功後頁面將會保留第一張靜止的畫面。playsinline是由於有些瀏覽器默認會開啟全屏播放,而全屏可能是畫面變成黑屏。

  webRTC大部分瀏覽器支持,IE(Edge)15+, Safari 11+, IOS Safari 11.2+, Android 64+, QQ、百度部分支持,對於IOS必須系統在11以上,並且只有Safari支持,UC 瀏覽器不支持。

  對於webRTC支持情況,可以采用以下代碼判斷。

if (navigator.mediaDevices === undefined ||
  navigator.mediaDevices.enumerateDevices 
=== undefined || navigator.mediaDevices.getUserMedia === undefined) { if (navigator.mediaDevices === undefined) { var fctName = ‘navigator.mediaDevices‘ } else if (navigator.mediaDevices.enumerateDevices === undefined) { var fctName = ‘navigator.mediaDevices.enumerateDevices‘ } else if
(navigator.mediaDevices.getUserMedia === undefined) { var fctName = ‘navigator.mediaDevices.getUserMedia‘ } else { console.assert(false) } alert(‘WebRTC issue-! ‘ + fctName + ‘ not present in your browser‘) }

  獲取video元素。

let video = document.querySelector(‘#video‘);

  如果支持webRTC,那麽就調用mediaDevice的方法來遍歷媒體對象,該方法返回一個promise對象,在第一個then方法的回調函數裏面默認接收返回的媒體信息。

navigator.mediaDevices.enumerateDevices().then(function (sourceInfos) {
})

  獲取sourceInfos,要拿到後置攝像頭的信息並不是通用的,PC、IOS、Android以及不同瀏覽器,處理方法都不同,這裏只做IOS和Android區分。

if(!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)) {
}

  如果不是IOS,那麽就需要遍歷sourceinfos,獲取後置攝像頭再獲取視頻流。聲明一個exArray用來存放不同媒體設備的id,再通過id獲取攝像頭信息。

let exArray = [];  
for (var i = 0; i < sourceInfos.length; ++i) {
  if (sourceInfos[i].kind == ‘videoinput‘) {
    exArray.push(sourceInfos[i].deviceId);
  }
}

  這樣數組裏面存放的都是攝像頭的id,而我們需要的是後置攝像頭,再調用獲取媒體信息的方法。

if (navigator.getUserMedia) {
  // 該方法可以傳遞3個參數,分別為獲取媒體信息的配置,成功的回調函數和失敗的回調函數
  navigator.getUserMedia({
    audio: false, // 表明是否獲取音頻
    video: {  // 對視頻信息進行配置
      optional: [{
        ‘sourceId‘: exArray[1] // 下標為0是前置攝像頭,1為後置攝像頭,所以PC不能進入該判斷,否則畫面會保持在第一幀不動
      }]
    },
  }, function successFunc(stream) {
    // 對FireFox進行兼容,這裏對返回流數據的處理不同
    if (video.mozSrcObject !== undefined) {
      //Firefox中,video.mozSrcObject最初為null,而不是未定義的,我們可以靠這個來檢測Firefox的支持  
      video.mozSrcObject = stream;
    } else {
      // 一般的瀏覽器需要使用createObjectURL對流數據進行處理,再交給video元素的src
      video.src = window.URL && window.URL.createObjectURL(stream) || stream;
    }
  }, function errorFunc(e) {
    alert(‘Error!‘ + e);
  }); //success是獲取成功的回調函數  
} else {
  alert(‘Native device media streaming (getUserMedia) not supported in this browser.‘);
}

  在成功的回調函數中,將返回的視頻流交給html中的video元素,這裏src的方式實際是通過blob64的格式來傳輸的。

  // ============================= IOS

  在IOS中獲取視頻流現實的方式又不一樣了,我們需要調用mediaDevice的獲取媒體的方法,這也是最新的標準。首先需要些小小的配置:

// 這裏對生成視頻進行配置
var userMediaConstraints = {
  audio: false, // 是否獲取音頻
  video: {
    facingMode: ‘environment‘,  // 環境表示後置攝像頭,使用user表示采用前置
    // 寬高的配置比較靈活,由於video一般都會顯示固定寬高比,所以使用ideal理想值即可
    width: {
      ideal: 1024,
      // min: 1024,
      // max: 1920
    },
    height: {
      ideal: 768,
      // min: 776,
      // max: 1080
    }
  }
}

  再調用方法獲取視頻就很簡單了,如下:

navigator.mediaDevices.getUserMedia(userMediaConstraints).then(function success(stream) {
  video.srcObject = stream;
}).catch(function (error) {
  alert(error.name + error.message)
});

  整體如下:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>web RTC</title>

</head>

<body>
  <!-- 這裏必須設置autoplay,否則視頻畫面靜止為第一張 -->
  <!-- 必須設置為playsinline,默認全屏播放可能會導致黑屏 -->
  <video id="video" autoplay playsinline></video>
  <script>
    // 習慣性寫在函數中,控制變量
   ;(function(){
    //  由於IOS必須在版本11以上才能使用webrtc,並且只有Safari支持,所以做一個小小的判斷,限定在
    if(/(iPhone|iPad|iPod|iOS)/i.test(window.navigator.userAgent) && navigator.vender.indexOf("apple") > -1) {
    return;
    }
    /**
     * =============實現在瀏覽器中打開攝像頭,並且將攝像頭內容顯示在頁面中
     * 想要實現這一功能,需要了解webRTC(Web Real-Time Communication)網絡實時通話技術,它允許瀏覽器實現視頻、音頻、P2P文件分享等功能。
     */
    // 開啟視頻功能,依賴window的navigator對象,采用getUserMedia方法,有版本差異,所以需要判斷區分
    // 需要IE(Edge)15+, Safari 11+, IOS Safari 11.2+, Android 64+, UC 不支持, QQ、百度部分支持

    // 所以首先需要對瀏覽器支持情況進行判斷
    // 先判斷瀏覽器是否支持
    if (navigator.mediaDevices === undefined ||
      navigator.mediaDevices.enumerateDevices === undefined ||
      navigator.mediaDevices.getUserMedia === undefined) {
      // 再判斷具體是那個方法不支持,並向用戶顯示
      if (navigator.mediaDevices === undefined) {
        var fctName = ‘navigator.mediaDevices‘
      } else if (navigator.mediaDevices.enumerateDevices === undefined) {
        var fctName = ‘navigator.mediaDevices.enumerateDevices‘
      } else if (navigator.mediaDevices.getUserMedia === undefined) {
        var fctName = ‘navigator.mediaDevices.getUserMedia‘
      } else {
        console.assert(false)
      }
      alert(‘WebRTC issue-! ‘ + fctName + ‘ not present in your browser‘)
    }
    const video = document.querySelector(‘#video‘)

    // 如果瀏覽器支持,該方法的更新是向後兼容,新版將所有功能都使用navigator.mediaDevices進行了封裝
    navigator.mediaDevices.enumerateDevices().then(function (sourceInfos) {
      // 如果支持新的方法,那麽就使用新的方法來獲取,當然這是一種比較主流的判斷方法
      // 如果是想舊的方法兼容,可以使用下面作為判斷條件,除IOS和PC以外,均使用舊的獲取方式
      // !(navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) || !/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent))
      
      /**
       * 無論是舊的寫法還是新的標準,思路都是通過設備信息,獲取攝像頭的視頻流,通過轉換變成blob的格式交給video的src
       */
      if (!navigator.mediaDevices.getUserMedia) {
        // 聲明一個數組,用於裝載設備媒體設備的相關信息,由於回調中sourceInfos對象中攜帶有所有媒體對象的相關信息
        // 這裏對信息進行遍歷篩選,只選出攝像頭的Id並保存在數組中
        var exArray = [];  
        for (var i = 0; i < sourceInfos.length; ++i) {
          if (sourceInfos[i].kind == ‘videoinput‘) {
            exArray.push(sourceInfos[i].deviceId);
          }
        }
        // 通過navigator的getUserMedia獲取攝像頭的視頻流,並在成功的回調中將視頻流交給video
        getMedia();

        function getMedia() {
          if (navigator.getUserMedia) {
            // 該方法可以傳遞3個參數,分別為獲取媒體信息的配置,成功的回調函數和失敗的回調函數
            navigator.getUserMedia({
              audio: false, // 表明是否獲取音頻
              video: {  // 對視頻信息進行配置
                optional: [{
                  ‘sourceId‘: exArray[1] // 下標為0是前置攝像頭,1為後置攝像頭,所以PC不能進入該判斷,否則畫面會保持在第一幀不動
                }]
              },
            }, successFunc, errorFunc); //success是獲取成功的回調函數  
          } else {
            alert(‘Native device media streaming (getUserMedia) not supported in this browser.‘);
          }
        }
        // 這裏是獲取媒體信息成功的回調函數
        function successFunc(stream) {
          // 對FireFox進行兼容,這裏對返回流數據的處理不同
          if (video.mozSrcObject !== undefined) {
            //Firefox中,video.mozSrcObject最初為null,而不是未定義的,我們可以靠這個來檢測Firefox的支持  
            video.mozSrcObject = stream;
          } else {
            // 一般的瀏覽器需要使用createObjectURL對流數據進行處理,再交給video元素的src
            video.src = window.URL && window.URL.createObjectURL(stream) || stream;
          }
        }
        // 獲取媒體信息失敗的回調
        function errorFunc(e) {
          alert(‘Error!‘ + e);
        }
      } else {  // 當采用最新的標準方式獲取視頻時
        // 這裏對生成視頻進行配置
        var userMediaConstraints = {
          audio: false, // 是否獲取音頻
          video: {
            facingMode: ‘environment‘  // 環境表示後置攝像頭,使用user表示采用前置
          }
        }
        // 這裏就采用新的方法來獲取視頻
        navigator.mediaDevices.getUserMedia(userMediaConstraints).then(function success(stream) {
          video.srcObject = stream;
 
        }).catch(function (error) {
          alert(error.name + error.message)
        });
      }
    }).catch(function(error) {
      alert(error.name + error.message)
    })
   })();
  </script>
</body>

</html>

  最後提供一個將視頻全屏顯示的方法,對於PC和要求不高的手機已經可以實現全屏

* {
    margin: 0;
}
body {
   overflow: hidden;
}
#video {
    min-width: 100%;
    min-height: 100%;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}

  在手機上,這個還有一點點橫向滾動條,要想完全去掉,需要改動html,讓video自動適用全屏的div

  html

<div id="wrapper">
  <video id="video" autoplay playsinline></video>
</div>

  css

* {
  margin: 0;
}

#wrapper {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
}

瀏覽器中打開攝像頭