问题:
//web rtc 调用摄像头(兼容性写法(谷歌、火狐、ie))
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
//调用成功会回调返回一个stream流 video:true 表示采集视频,audio:true 表示采集声音,反之就都不采集。
navigator.getUserMedia({video:true,audio:false},function(stream){
//将采集到的视频信息显示在video标签中
video.srcObject = stream;
},console.log)原文链接:https://blog.csdn.net/xiehuanbin/article/details/131512316
navigator.mediaDevices is undefined 会报错,得知因为加密的安全性问题:
目前查到的解决办法如下:
1. 使用https协议,需要域名
2. 手动修改本机浏览器配置【chrome://flags/ 】,多个地址用【,】隔开,修改后底部会提示重启浏览器
3.localhost 域
本地文件以file 形式打开时
其他情况下你在浏览器里log这个API都是返回undefined.
如果想要 HTTP 环境下也能使用和调试 MediaDevices.getUserMedia(),通过开启 Chrome 的相应参数,也是可以实现的。
传递相应参数来启动 Chrome,-unsafely-treat-insecure-origin-as-secure="http://example.com"
链接:https://www.jianshu.com/p/b59ac832a00a
1.第一种
业务逻辑需要人脸验证,需要通过调用摄像头获取人脸来调用接口做对比,所以学习了一下js关于调用摄像头拍照。主要通过video调用摄像头和canvas截取画面。
let video = document.querySelector('.video');
let canvas = document.querySelector('canvas');
function openx() {
let constraints = {
video: { //这里是摄像头的信息
height: 500,
width: 500
},
// audio: true, //是否开启麦克风
}
let isok = navigator.mediaDevices.getUserMedia(constraints); //这里主要是用于请求用户打开摄像头的权限
isok.then(res => { //可以看出是使用promise封装的 那么我们就可以使用then和catch
video.srcObject = res; //用户允许时 将摄像头对象的画面转移到video上面
video.play(); //打开video的画面
}).catch((err) => {
console.log(err) //拒绝时打印错误信息
})
}
function pho() {
canvas.getContext("2d").drawImage(video, 0, 0, 300, 300); //第一个参数为要截取的dom对象,第二个和第三个为xy轴的偏移值 3-4为截取图像的大小
}
function exit() {
video.srcObject.getTracks()[0].stop(); //这里如果打开了麦克风、getTracks是一个数组,我们同样需要获取下标[1]来关闭摄像头 打开麦克风[0]就是麦克风
}
View Code
上述代码看起来并不多,包含了打开-截取图像-关闭 摄像头的功能,足以满足功能需求。
https://blog.csdn.net/m0_72436362/article/details/128321359
外接摄像头没错,笔记本的摄像头报错,放form标签里有问题,不显示
$("img").css("src", canvas.toDataURL("image/png"));
2.第二种,笔记本的摄像头打开没报错
.booth {
width:400px;
background:#ccc;
border: 10px solid #ddd;
margin: 0 auto;
}
获取用户媒体:
navigator.mediaDevices.getUserMedia({video: true, audio: true}) // 异步操作
枚举媒体数:video,audio输入输出设备
navigator.mediaDevices.enumerateDevices() // 异步操作
let convas = document.querySelector("#canvas"); //
let video = document.querySelector("#video");
let audio = document.querySelector("audio");
let img = document.querySelector("#img");
let btn = document.querySelector("button");
let context = canvas.getContext('2d');
let width = 320; //视频和canvas的宽度
let height = 0; //
let streaming = false; // 是否开始捕获媒体
// 获取用户媒体,包含视频和音频
navigator.mediaDevices.getUserMedia({video: true, audio: true})
.then(stream => {
video.srcObject = stream; // 将捕获的视频流传递给video 放弃window.URL.createObjectURL(stream)的使用
video.play(); // 播放视频
audio.srcObject = stream;
audio.play();
});
function tackcapture() {
// 需要判断媒体流是否就绪
if(streaming){
context.drawImage(video, 0, 0, 350, 200);// 将视频画面捕捉后绘制到canvas里面
img.src = canvas.toDataURL('image/png');// 将canvas的数据传送到img里
}
}
btn.addEventListener('click',tackcapture,false); // 按钮点击事件
// 监听视频流就位事件,即视频可以播放了
video.addEventListener('canplay', function(ev){
if (!streaming) {
height = video.videoHeight / (video.videoWidth/width);
video.setAttribute('width', width);
video.setAttribute('height', height);
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
streaming = true;
}
}, false);
View Code
有些浏览器可能不支持此功能
必须通过服务器打开页面,通过files://打开无效
如果通过远程服务器打开则必须是https协议, http协议也无法使用
转:https://www.cnblogs.com/scarecrowlxb/p/6804747.html
3.第三种
* {
margin: 0;
padding: 0;
}
video {
width: 200px;
}
button {
width: 100px;
height: 60px;
}
// 视频大小
var constraints = { audio: true, video: { width: 200, height: 250 } };
// 开启视频
navigator.mediaDevices
.getUserMedia(constraints)
.then(function(mediaStream) {
console.log("getUserMedia:", mediaStream);
var video = document.querySelector("video");
video.srcObject = mediaStream;
video.onloadedmetadata = function(e) {
video.play();
};
// 使用canvas进行拍照
var canvas = document.getElementById("canvas");
$("button").on("click", function() {
canvas.getContext("2d").drawImage(video, 0, 0, 200, 250);
$("img").css("src", canvas.toDataURL("image/png"));
});
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
});
View Code
转:http://www.taodudu.cc/news/show-6195164.html?action=onClick
https://811w1z2xwj.codesandbox.io/
4.第四种
let mediaStreamTrack = null; // 视频对象(全局)
function openMedia() {
let constraints = {
video: {
width: 500,
height: 500
},
audio: true
};
//获得video摄像头
let video = document.getElementById('video');
let promise = navigator.mediaDevices.getUserMedia(constraints);
promise.then((mediaStream) => {
mediaStreamTrack = typeof mediaStream.stop === 'function' ? mediaStream : mediaStream.getTracks()[1];
video.srcObject = mediaStream;
video.play();
});
}
// 拍照
function takePhoto() {
//获得Canvas对象
let video = document.getElementById('video');
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
ctx.drawImage(video, 0, 0, 500, 500);
// toDataURL --- 可传入'image/png'---默认, 'image/jpeg'
let img = document.getElementById('canvas').toDataURL();
// 这里的img就是得到的图片
console.log('img-----', img);
document.getElementById('imgTag').src = img;
}
// 关闭摄像头
function closeMedia() {
mediaStreamTrack.stop();
}
View Code
5. 调用用户的摄像头
调用电脑摄像头功能,经过在网上查找资料有以下三种方案实现。
通过浏览器API来getUserMedia来实现调用用户的摄像头,但有两点限制:部署到生产服务的时候要使用htts协议访问该项目,第二点限制就是第一次获取摄像头时要点击允许弹窗。
通过web端发送websocket请求给客户端,然后客户端调用摄像头应用程序,但每次初始打开摄像头应用时都有个初始化2~3秒左右,用户体验不免友好。
通过客户端获取摄像头的每一帧数据,并通过websocket返回给web端,具体步骤下面有代码讲解。
getUserMedia方式实现代码
var video = document.querySelector('#video');
var startRecord = document.querySelector('#startRecord');
var stopRecord = document.querySelector('#stopRecord');
var mediaRecorder;
var chunks = [];
navigator.mediaDevices.getUserMedia({ audio: false, video: true }).then(function (stream) {
video.srcObject = stream;
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = function (e) {
chunks.push(e.data);
};
mediaRecorder.onstop = function (e) {
var blob = new Blob(chunks, { type: 'video/mp4' });
chunks = [];
var videoURL = window.URL.createObjectURL(blob);
video.src = videoURL;
};
});
startRecord.onclick = function () {
mediaRecorder.start();
};
stopRecord.onclick = function () {
mediaRecorder.stop();
};
View Code
客户端返回视频流方式实现代码
vue前端代码前端接收到H264视频流,需要用JMuxer来转码才能在video标签里播放,需要执行npm install JMuxer来安装这个库。详细代码如下:
import JMuxer from 'jmuxer';
import { onMounted, onBeforeUnmount} from 'vue';
var ws = null;
var jmuxer = null;
const list = reactive([]);
const isDisable = ref(false);
onMounted(() => {
jmuxer = new JMuxer({
node: 'player',
// 可用值是:video、audio
mode: 'video',
// 最大延迟时间(毫秒), 默认为值是500毫秒
maxDelay: 100,
// 缓冲区刷新时间,默认为值是500毫秒
flushingTime: 0,
// 是否会自动清除播放的媒体缓冲区。默认为true
clearBuffer: true,
// 可选值。视频的帧率,如果它是已知的或固定值。如果所提供的媒体数据中没有块持续时间,它将用于查找帧持续时间。
fps: 30,
// 将从MP4轨道数据读取FPS,而不是使用(以上)FPS值。默认为false。
readFpsFromTrack: false,
// 将在浏览器控制台打印调试日志。默认为false
debug: false,
// 遇到任何丢失的视频帧将会被触发
onMissingVideoFrames: function (data) {
console.log('丢失的视频帧');
},
onError: function (data) {
if (/Safari/.test(navigator.userAgent) && /Apple Computer/.test(navigator.vendor)) {
jmuxer.reset();
}
}
});
ws = new WebSocket('ws://127.0.0.1:12797');
ws.binaryType = 'arraybuffer';
ws.onmessage = function (event) {
jmuxer.feed({ video: new Uint8Array(event.data) });
};
ws.onopen = function () {
console.log('已连接');
ws.send('{"interfaceId":"100002","command":"1"}');
};
ws.onerror = function (err) {
console.log('出错--Socket Error', err);
};
ws.onclose = function () {
console.log('断开');
};
});
// 实现拍照功能
const toScan = () => {
const videoEl = document.getElementById('player');
const canvas = document.createElement('canvas');
canvas.width = videoEl.videoWidth;
canvas.height = videoEl.videoHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(videoEl, 0, 0, videoEl.videoWidth, videoEl.videoHeight);
console.log(canvas.toDataURL('image/png'));
};
onBeforeUnmount(() => {
console.info('离开页面,关闭高拍仪');
ws.close();
jmuxer.destroy();
});
View Code
链接:https://www.jianshu.com/p/e929fe5f8c35
6.这个里面比较多
https://blog.csdn.net/Nine_91/article/details/126173990?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-126173990-blog-80924677.235^v38^pc_relevant_default_base3&spm=1001.2101.3001.4242.1&utm_relevant_index=3
body{overflow-y:auto;overflow-x:auto;margin:0;}
#cameraBtn,#cameraDiv{padding:5px;}
.big-btn-blue{ display:inline-block; min-width:80px; height:30px; margin:0 5px; padding:0 15px; vertical-align:top; line-height:30px; text-align:center; font-size:14px; font-family: "微软雅黑";
color:#fff; border-radius:2px; box-sizing:border-box; -moz-box-sizing:border-box; -webkit-box-sizing:border-box; cursor:pointer; }
.big-btn-blue{ -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; transition: all 0.3s ease;}/*动画*/
.big-btn-blue{ border:1px solid #3194dd; background-color:#3194dd;}/*纯蓝色*/
//访问用户媒体设备的兼容方法
function getUserMedia(constrains,success,error){
if(navigator.mediaDevices.getUserMedia){
//最新标准API
navigator.mediaDevices.getUserMedia(constrains).then(success).catch(error);
} else if (navigator.webkitGetUserMedia){
//webkit内核浏览器
navigator.webkitGetUserMedia(constrains).then(success).catch(error);
} else if (navigator.mozGetUserMedia){
//Firefox浏览器
navagator.mozGetUserMedia(constrains).then(success).catch(error);
} else if (navigator.getUserMedia){
//旧版API
navigator.getUserMedia(constrains).then(success).catch(error);
}else{
alert("不支持的浏览器");
}
}
//成功的回调函数
function success(stream){
//兼容webkit内核浏览器
var CompatibleURL = window.URL || window.webkitURL;
//将视频流设置为video元素的源
try {
video.srcObject = stream;
} catch (e) {
video.src = CompatibleURL.createObjectURL(stream);
}
//播放视频
video.play();
}
//异常的回调函数
function error(error){
alert("访问用户媒体设备失败,"+error.name+""+error.message);
}
/**
* 获取当前静态页面的参数
* 返回值和使用方法类似java request的getparamater
* 不同: 当取得的为数组(length>1)时调用toString()返回(逗号分隔每个元素)
* @param {Object} name
* @return {TypeName}
*/
function getPara(name,search){
var p = getParas(name,search);
if(p.length==0){
return null;
}else if(p.length==1){
return p[0];
}else{
return p.toString();
}
}
/**获取当前静态页面的参数
* 返回值和使用方法类似java request的getparamaterValues
* @param {Object} name 要取出的参数名,可以在参数字符串中重复出现
* @param {Object} search 手工指定要解析的参数字符串,默认为当前页面后跟的参数
* @return {TypeName}
*/
function getParas(name,search){
if(!search){
search = window.location.search.substr(1);//1.html?a=1&b=2
}
var para = [];
var pairs = search.split("&");//a=1&b=2&b=2&c=2&b=2
for(var i=0;i var sign = pairs[i].indexOf("="); if(sign == -1){//如果没有找到=号,那么就跳过,跳到下一个字符串(下一个循环)。 continue; } var aKey = pairs[i].substring(0,sign); if(aKey==name){ para.push(unescape(pairs[i].substring(sign+1))); } } return para; } //开启摄像头 function captureInit(){ if ((navigator.mediaDevices!=undefined && navigator.mediaDevices.getUserMedia!=undefined) || navigator.getUserMedia!=undefined || navigator.webkitGetUserMedia!=undefined || navigator.mozGetUserMedia!=undefined){ document.getElementById("help").style.display="none"; //调用用户媒体设备,访问摄像头,改为触发事件 getUserMedia({video:{width:imgWidth,height:imgHeight}},success,error); if(captureState==0){ captureState=1;//标记此按钮已点击 } } else { captureState=0;//异常标识按钮没点 alert("你的浏览器不支持访问用户媒体设备或访问地址不是https开头,您可以点击右侧下载解决方案"); document.getElementById("help").style.display="inline-block"; } } //注册拍照按钮的单击事件 function capture(){ //绘制画面 if(captureState==0){ alert("请先开启摄像头"); return; } context.drawImage(video,0,0,imgWidth,imgHeight);//后面两个长宽 //canvas.toDataURL("image/png");//即可得到base64编码 captureState=2; } //确认按钮返回给父页面的函数 function queren(){ if(captureState!=2){ alert("请先开启摄像头并拍照"); return; } var base64=canvas.toDataURL("image/jpeg"); var pics={}; pics.filetypeid=filetypeid;//返回给前端 pics.base64=base64; if(window.opener){ window.opener[cb](pics);// /FileUploadTmp/为项目临时文件夹相对路径 window.close(); }else if(window.parent){ window.parent[cb](pics); window.parent.$("#dialog_ifr_html").dialog("close");//close会导致flash未执行完就销毁,页面JS报错 }else{ window.close(); } }
var cb=getPara("cb")||"setImg";
var filetypeid=getPara("filetypeid")||"filetypeid";//附件类型id
var video=document.getElementById("video");
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
var imgWidth=getPara("width")||"300";//这个值div的宽一致
var imgHeight=getPara("height")||"200";//这个值div的高一致
var captureState=0;//未开启,1已开启,2已拍照,为2才可点击确认按钮
var style = getPara("style")||"big-btn-blue";
video.style.width=imgWidth;
video.style.height=imgHeight;
var st = style.split(",");
document.getElementById("init").className=st[0];
document.getElementById("capture").className=st[1]||st[0];
document.getElementById("queren").className=st[2]||st[0];
document.getElementById("help").className=st[3]||st[0];
View Code