webcam.js 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. class Webcam {
  2. constructor(webcamElement, facingMode = 'user', canvasElement = null, snapSoundElement = null) {
  3. this._webcamElement = webcamElement;
  4. // this._webcamElement.width = this._webcamElement.width || 640;
  5. // this._webcamElement.height = this._webcamElement.height || this._webcamElement.width * (3 / 4);
  6. this._facingMode = facingMode;
  7. this._webcamList = [];
  8. this._streamList = [];
  9. this._selectedDeviceId = '';
  10. this._canvasElement = canvasElement;
  11. this._snapSoundElement = snapSoundElement;
  12. this._webcamIndex = 0;
  13. }
  14. get facingMode(){
  15. return this._facingMode;
  16. }
  17. set facingMode(value){
  18. this._facingMode = value;
  19. }
  20. get webcamList(){
  21. return this._webcamList;
  22. }
  23. get webcamCount(){
  24. return this._webcamList.length;
  25. }
  26. get selectedDeviceId(){
  27. return this._selectedDeviceId;
  28. }
  29. /* Get all video input devices info */
  30. getVideoInputs(mediaDevices){
  31. this._webcamList = [];
  32. mediaDevices.forEach(mediaDevice => {
  33. if (mediaDevice.kind === 'videoinput') {
  34. this._webcamList.push(mediaDevice);
  35. }
  36. });
  37. if(this._webcamList.length == 1){
  38. this._facingMode = 'user';
  39. }
  40. return this._webcamList;
  41. }
  42. /* Get media constraints */
  43. getMediaConstraints() {
  44. var videoConstraints = {};
  45. if (this._selectedDeviceId == '') {
  46. videoConstraints.facingMode = this._facingMode;
  47. } else {
  48. videoConstraints.deviceId = { exact: this._selectedDeviceId};
  49. }
  50. var constraints = {
  51. video: videoConstraints,
  52. audio: false
  53. };
  54. console.log('mediaConstraints:', constraints);
  55. console.log('selectedDeviceId:', this._selectedDeviceId);
  56. console.log('webcamIndex:', this._webcamIndex);
  57. return constraints;
  58. }
  59. /* Select camera based on facingMode */
  60. selectCamera(){
  61. for(let webcam of this._webcamList){
  62. if( (this._facingMode=='user' && (webcam.label.toLowerCase().includes('front') || webcam.label.toLowerCase().includes('前置')))
  63. || (this._facingMode=='enviroment' && (webcam.label.toLowerCase().includes('back') || webcam.label.toLowerCase().includes('後置')))
  64. )
  65. {
  66. this._selectedDeviceId = webcam.deviceId;
  67. break;
  68. }
  69. }
  70. }
  71. /* Change Facing mode and selected camera */
  72. flip(){
  73. const curremtDeviceId = this._selectedDeviceId;
  74. this._facingMode = (this._facingMode == 'user')? 'enviroment': 'user';
  75. this._webcamElement.style.transform = "";
  76. this.selectCamera();
  77. if (curremtDeviceId !== this._selectedDeviceId) return;
  78. if (this._webcamList.filter(item => item.label === '').length === 0) return;
  79. console.log('webcam.label is empty!!!');
  80. if (!this._selectedDeviceId) {
  81. this._selectedDeviceId = this._webcamList[0].deviceId;
  82. this._webcamIndex = 0;
  83. }
  84. let index = 0
  85. if (this._webcamList.length >= 4 && this._webcamList.length % 2 === 0) {
  86. index = this._webcamIndex + 2;
  87. } else {
  88. index = this._webcamIndex + 1;
  89. }
  90. if (index > this._webcamList.length - 1) {
  91. index = 0;
  92. }
  93. this._selectedDeviceId = this._webcamList[index].deviceId;
  94. this._webcamIndex = index;
  95. }
  96. /*
  97. 1. Get permission from user
  98. 2. Get all video input devices info
  99. 3. Select camera based on facingMode
  100. 4. Start stream
  101. */
  102. async start(startStream = true) {
  103. return new Promise((resolve, reject) => {
  104. this.stop();
  105. if (navigator.mediaDevices === undefined || navigator.mediaDevices.enumerateDevices === undefined || navigator.mediaDevices.getUserMedia === undefined) {
  106. if (navigator.mediaDevices === undefined) {
  107. var fctName = 'navigator.mediaDevices';
  108. }
  109. else if (navigator.mediaDevices.enumerateDevices === undefined) {
  110. var fctName = 'navigator.mediaDevices.enumerateDevices';
  111. }
  112. else if (navigator.mediaDevices.getUserMedia === undefined) {
  113. var fctName = 'navigator.mediaDevices.getUserMedia';
  114. }
  115. else {
  116. console.assert(false);
  117. }
  118. reject('WebRTC issue-! ' + fctName + ' not present in your browser');
  119. console.log('navigator:', navigator);
  120. return;
  121. }
  122. console.log('webcam','getUserMedia');
  123. navigator.mediaDevices.getUserMedia(this.getMediaConstraints()) //get permisson from user
  124. .then(stream => {
  125. this._streamList.push(stream);
  126. this.info() //get all video input devices info
  127. .then(webcams =>{
  128. console.log("webcamList:", this._webcamList);
  129. this.selectCamera(); //select camera based on facingMode
  130. if(startStream){
  131. console.log('webcam','startStream');
  132. this.stream()
  133. .then(facingMode =>{
  134. resolve(this._facingMode);
  135. })
  136. .catch(error => {
  137. reject('Stream Error\nName: ' + error.name + '\nMessage: ' + error.message);
  138. });
  139. }else{
  140. resolve(this._selectedDeviceId);
  141. }
  142. })
  143. .catch(error => {
  144. reject('EnumerateDevices Error\nName: ' + error.name + '\nMessage: ' + error.message);
  145. });
  146. })
  147. .catch(error => {
  148. const response = {
  149. 'PermissionDeniedError': '瀏覽器禁止本頁面使用攝像頭,請開啟相關的許可權',
  150. 'NotAllowedError': '瀏覽器禁止本頁面使用攝像頭,請開啟相關的許可權',
  151. 'ConstraintNotSatisfiedError': '您的設備不支持該分辨率。',
  152. }
  153. reject('getUserMedia Error\nName: ' + error.name + '\nMessage: ' + error.message);
  154. });
  155. });
  156. }
  157. /* Get all video input devices info */
  158. async info(){
  159. return new Promise((resolve, reject) => {
  160. navigator.mediaDevices.enumerateDevices()
  161. .then(devices =>{
  162. this.getVideoInputs(devices);
  163. resolve(this._webcamList);
  164. })
  165. .catch(error => {
  166. reject(error);
  167. });
  168. });
  169. }
  170. /* Start streaming webcam to video element */
  171. async stream() {
  172. return new Promise((resolve, reject) => {
  173. navigator.mediaDevices.getUserMedia(this.getMediaConstraints())
  174. .then(stream => {
  175. this._streamList.push(stream);
  176. this._webcamElement.srcObject = stream;
  177. if(this._facingMode == 'user'){
  178. this._webcamElement.style.transform = "scale(-1,1)";
  179. }
  180. // this._webcamElement.play();
  181. resolve(this._facingMode);
  182. })
  183. .catch(error => {
  184. reject(error);
  185. });
  186. });
  187. }
  188. /* Stop streaming webcam */
  189. stop() {
  190. this._streamList.forEach(stream => {
  191. stream.getTracks().forEach(track => {
  192. track.stop();
  193. });
  194. });
  195. }
  196. snap() {
  197. return new Promise((resolve,reject ) => {
  198. if(this._canvasElement!=null){
  199. if(this._snapSoundElement!= null){
  200. this._snapSoundElement.play();
  201. }
  202. this._canvasElement.width = this._webcamElement.clientWidth;
  203. this._canvasElement.height = this._webcamElement.clientHeight;
  204. let context = this._canvasElement.getContext('2d');
  205. if(this._facingMode == 'user'){
  206. context.translate(this._canvasElement.width, 0);
  207. context.scale(-1, 1);
  208. }
  209. context.clearRect(0, 0, this._canvasElement.width, this._canvasElement.height);
  210. context.drawImage(this._webcamElement, 0, 0, this._canvasElement.width, this._canvasElement.height);
  211. let data = this._canvasElement.toDataURL('image/png', 1.0);
  212. resolve(data);
  213. }
  214. else{
  215. reject("Snap Error\ncanvas element is missing");
  216. }
  217. });
  218. }
  219. }