123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- class Webcam {
- constructor(webcamElement, facingMode = 'user', canvasElement = null, snapSoundElement = null) {
- this._webcamElement = webcamElement;
- // this._webcamElement.width = this._webcamElement.width || 640;
- // this._webcamElement.height = this._webcamElement.height || this._webcamElement.width * (3 / 4);
- this._facingMode = facingMode;
- this._webcamList = [];
- this._streamList = [];
- this._selectedDeviceId = '';
- this._canvasElement = canvasElement;
- this._snapSoundElement = snapSoundElement;
- this._webcamIndex = 0;
- }
-
- get facingMode(){
- return this._facingMode;
- }
-
- set facingMode(value){
- this._facingMode = value;
- }
-
- get webcamList(){
- return this._webcamList;
- }
-
- get webcamCount(){
- return this._webcamList.length;
- }
-
- get selectedDeviceId(){
- return this._selectedDeviceId;
- }
-
- /* Get all video input devices info */
- getVideoInputs(mediaDevices){
- this._webcamList = [];
- mediaDevices.forEach(mediaDevice => {
- if (mediaDevice.kind === 'videoinput') {
- this._webcamList.push(mediaDevice);
- }
- });
- if(this._webcamList.length == 1){
- this._facingMode = 'user';
- }
- return this._webcamList;
- }
-
- /* Get media constraints */
- getMediaConstraints() {
- var videoConstraints = {};
- if (this._selectedDeviceId == '') {
- videoConstraints.facingMode = this._facingMode;
- } else {
- videoConstraints.deviceId = { exact: this._selectedDeviceId};
- }
- var constraints = {
- video: videoConstraints,
- audio: false
- };
- console.log('mediaConstraints:', constraints);
- console.log('selectedDeviceId:', this._selectedDeviceId);
- console.log('webcamIndex:', this._webcamIndex);
- return constraints;
- }
-
- /* Select camera based on facingMode */
- selectCamera(){
- for(let webcam of this._webcamList){
- if( (this._facingMode=='user' && (webcam.label.toLowerCase().includes('front') || webcam.label.toLowerCase().includes('前置')))
- || (this._facingMode=='enviroment' && (webcam.label.toLowerCase().includes('back') || webcam.label.toLowerCase().includes('後置')))
- )
- {
- this._selectedDeviceId = webcam.deviceId;
- break;
- }
- }
- }
-
- /* Change Facing mode and selected camera */
- flip(){
- const curremtDeviceId = this._selectedDeviceId;
- this._facingMode = (this._facingMode == 'user')? 'enviroment': 'user';
- this._webcamElement.style.transform = "";
- this.selectCamera();
- if (curremtDeviceId !== this._selectedDeviceId) return;
- if (this._webcamList.filter(item => item.label === '').length === 0) return;
-
- console.log('webcam.label is empty!!!');
-
- if (!this._selectedDeviceId) {
- this._selectedDeviceId = this._webcamList[0].deviceId;
- this._webcamIndex = 0;
- }
-
- let index = 0
- if (this._webcamList.length >= 4 && this._webcamList.length % 2 === 0) {
- index = this._webcamIndex + 2;
- } else {
- index = this._webcamIndex + 1;
- }
-
- if (index > this._webcamList.length - 1) {
- index = 0;
- }
-
- this._selectedDeviceId = this._webcamList[index].deviceId;
- this._webcamIndex = index;
- }
-
- /*
- 1. Get permission from user
- 2. Get all video input devices info
- 3. Select camera based on facingMode
- 4. Start stream
- */
- async start(startStream = true) {
- return new Promise((resolve, reject) => {
- this.stop();
- 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);
- }
- reject('WebRTC issue-! ' + fctName + ' not present in your browser');
- console.log('navigator:', navigator);
- return;
- }
- console.log('webcam','getUserMedia');
- navigator.mediaDevices.getUserMedia(this.getMediaConstraints()) //get permisson from user
- .then(stream => {
- this._streamList.push(stream);
- this.info() //get all video input devices info
- .then(webcams =>{
- console.log("webcamList:", this._webcamList);
- this.selectCamera(); //select camera based on facingMode
- if(startStream){
- console.log('webcam','startStream');
- this.stream()
- .then(facingMode =>{
- resolve(this._facingMode);
- })
- .catch(error => {
- reject('Stream Error\nName: ' + error.name + '\nMessage: ' + error.message);
- });
- }else{
- resolve(this._selectedDeviceId);
- }
- })
- .catch(error => {
- reject('EnumerateDevices Error\nName: ' + error.name + '\nMessage: ' + error.message);
- });
- })
- .catch(error => {
- const response = {
- 'PermissionDeniedError': '瀏覽器禁止本頁面使用攝像頭,請開啟相關的許可權',
- 'NotAllowedError': '瀏覽器禁止本頁面使用攝像頭,請開啟相關的許可權',
- 'ConstraintNotSatisfiedError': '您的設備不支持該分辨率。',
- }
- reject('getUserMedia Error\nName: ' + error.name + '\nMessage: ' + error.message);
- });
- });
- }
-
- /* Get all video input devices info */
- async info(){
- return new Promise((resolve, reject) => {
- navigator.mediaDevices.enumerateDevices()
- .then(devices =>{
- this.getVideoInputs(devices);
- resolve(this._webcamList);
- })
- .catch(error => {
- reject(error);
- });
- });
- }
-
- /* Start streaming webcam to video element */
- async stream() {
- return new Promise((resolve, reject) => {
- navigator.mediaDevices.getUserMedia(this.getMediaConstraints())
- .then(stream => {
- this._streamList.push(stream);
- this._webcamElement.srcObject = stream;
- if(this._facingMode == 'user'){
- this._webcamElement.style.transform = "scale(-1,1)";
- }
- // this._webcamElement.play();
- resolve(this._facingMode);
- })
- .catch(error => {
- reject(error);
- });
- });
- }
-
- /* Stop streaming webcam */
- stop() {
- this._streamList.forEach(stream => {
- stream.getTracks().forEach(track => {
- track.stop();
- });
- });
- }
-
- snap() {
- return new Promise((resolve,reject ) => {
- if(this._canvasElement!=null){
- if(this._snapSoundElement!= null){
- this._snapSoundElement.play();
- }
- this._canvasElement.width = this._webcamElement.clientWidth;
- this._canvasElement.height = this._webcamElement.clientHeight;
- let context = this._canvasElement.getContext('2d');
- if(this._facingMode == 'user'){
- context.translate(this._canvasElement.width, 0);
- context.scale(-1, 1);
- }
- context.clearRect(0, 0, this._canvasElement.width, this._canvasElement.height);
- context.drawImage(this._webcamElement, 0, 0, this._canvasElement.width, this._canvasElement.height);
- let data = this._canvasElement.toDataURL('image/png', 1.0);
- resolve(data);
- }
- else{
- reject("Snap Error\ncanvas element is missing");
- }
- });
- }
- }
|