调用前置摄像头 capture="user" 调用后置摄像头capture="environment"或其他只适用于ios
根据官网解释
iOS最遵守遵守HTML5规范,其次是X5内核,安卓的webview基本忽略了capture。
官方文档:www.w3.org/TR/2018/REC-html-media-capture-20180201/
对于安卓,亲测capture="user"效果是,第一次打开前置摄像无效,默认还是后置,需要你在第一次打开相机后手动翻转摄像头,后面再打开才会默认前置
<input
class="file"
id="uploadFile"
type="file"
name="image"
accept="image/*"//accept="audio/*"录音"video/*"视频时capture只有两种值,
//一种是user 一种是environment
capture="user"
/>
对于安卓用navigator.mediaDevices的getUserMedia
注:!!!必须在https环境下navigator.mediaDevices才生效,在本地调试http环境navigator.mediaDevices为undefined
API文档:MediaDevices.getUserMedia() - Web API 接口参考 | MDN
基础使用(自行封装成方法或放在生命周期,如:vue mounted里可看效果)
// var constraints={audio: true, video{ width: 1280, height: 720 }}
var constraints={audio: true, video:true}//audio:true&false打开&关闭音频 video:true&false打开&关闭视频
// video{ width: 1280, height: 720 }设置1280x720的摄像头分辨率,不需要再设置video:true,设置分辨率时默认true
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
/* 使用这个 stream stream */
var video = document.querySelector("video");//自行创建id="video"的video标签作为相机容器
video.srcObject = mediaStream;
video.onloadedmetadata = function (e) {
// video.play();打开播放
};
})
.catch(function(err) {
/* 处理 error */
});
vue前置拍照功能实现(复制可用,亲测有效)
<template>
<div class="publish">
<video ref="video"></video>
<canvas style="display: none" id="canvasCamera"></canvas>
<div v-if="imgSrc" class="img_bg_camera">
<img :src="imgSrc" class="tx_img" />
</div>
<button @click="OpenCamera">打开摄像头</button>
<button @click="CloseCamera">关闭摄像头</button>
<button @click="setImage">拍照</button>
</div>
</template>
<script>
export default {
data() {
return {
mediaStreamTrack: {},
video_stream: "", // 视频stream
imgSrc: "", // 拍照图片
canvas: null,
context: null,
};
},
mounted() {
// 进入页面 自动调用摄像头
this.getCamera();
},
methods: {
// 调用打开摄像头功能
getCamera() {
// 获取 canvas 画布
this.canvas = document.getElementById("canvasCamera");
this.context = this.canvas.getContext("2d");
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
// 正常支持版本
navigator.mediaDevices
.getUserMedia({
video: true,
audio: false,
})
.then((stream) => {
// 摄像头开启成功
this.mediaStreamTrack =
typeof stream.stop === "function" ? stream : stream.getTracks()[0];
this.video_stream = stream;
this.$refs.video.srcObject = stream;
this.$refs.video.play();
})
.catch((err) => {
console.log(err);
});
},
// 拍照 绘制图片
setImage() {
// 点击canvas画图
this.context.drawImage(this.$refs.video, 0, 0, 200, 100);
console.log("拍照", this.context.drawImage);
// 获取图片base64链接 canvas
this.canvas = document.getElementById("canvasCamera");
this.canvas.style.display = "block";
console.log(this.canvas, "拍照 image ", this.canvas.style);
const image = this.cancas.toDataURL("image/png");
this.imgSrc = image;
console.log(this.imgSrc, "拍照 image ", image);
// this.$emit("refreshDataList", this.imgSrc);
},
// 打开摄像头
OpenCamera() {
console.log("打开摄像头");
this.getCamera();
},
// 关闭摄像头
CloseCamera() {
console.log("关闭摄像头");
this.$refs.video.srcObject.getTracks()[0].stop();
},
},
};
</script>
<style scoped>
video {
width: 100%;
height: 300px;
}
canvas {
width: 100%;
height: 300px;
}
button {
width: 100px;
height: 40px;
position: relative;
bottom: 0;
left: 0;
background-color: rgb(22, 204, 195);
}
.img_bg_camera img {
width: 300px;
height: 200px;
}
</style>
h5拍照(无亲测)
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>摄像头拍照</title>
</head>
<body onload='init()'>
<video id="video">
</video>
<div id='operators'>
<button id="capture">拍照</button> <button id="changeCamera">切换摄像头</button>
</div>
<canvas id="canvas" width="480" height="320"></canvas>
<script>
var cameraFront="";
//访问用户媒体设备的兼容方法
function getUserMedia(constraints, success, error) {
currentCamera=constraints;
if (navigator.mediaDevices.getUserMedia) {
//最新的标准API
navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
} else if (navigator.webkitGetUserMedia) {
//webkit核心浏览器
navigator.webkitGetUserMedia(constraints,success, error)
} else if (navigator.mozGetUserMedia) {
//firfox浏览器
navigator.mozGetUserMedia(constraints, success, error);
} else if (navigator.getUserMedia) {
//旧版API
navigator.getUserMedia(constraints, success, error);
}
}
let video = document.getElementById('video');
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
//视频流变量
var localMediaStream;
function success(stream) {
//兼容webkit核心浏览器
let CompatibleURL = window.URL || window.webkitURL;
//将视频流设置为video元素的源
console.log(stream);
//video.src = CompatibleURL.createObjectURL(stream);
video.srcObject = stream;
video.play();
localMediaStream=stream;
}
function error(error) {
alert(`访问用户媒体设备失败${error.name}, ${error.message}`);
}
if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia) {
//调用用户媒体设备, 访问摄像头 video和audio: {video : {width: 480, height: 320}} 使用前置摄像头, 代码如下: {video: {facingMode: 'user'}} 后置摄像头, 代码如下: {video: {facingMode: {exact : 'environment'}}}
getUserMedia({audio: true,video: {facingMode: {exact : 'environment'}}}, success, error);
} else {
alert('不支持访问用户媒体');
}
document.getElementById('capture').addEventListener('click', function () {
context.drawImage(video, 0, 0, 480, 320);
})
//当前摄像头
var currentCamera;
document.getElementById('changeCamera').addEventListener('click', function () {
//关闭打开的摄像头
localMediaStream.getTracks().forEach(function(track) {
track.stop();
});
if(currentCamera.video.facingMode=='user')
{
getUserMedia({audio: true,video: {facingMode: {exact : 'environment'}}}, success, error);
}else{
getUserMedia({audio: true,video: {facingMode: 'user'}}, success, error);
}
})
function init(){
document.getElementById('operators').style.width=document.getElementById('video').style.width;
document.getElementById('operators').style.textAlign="center";
}
</script>
</body>
</html>
vue视频录制(无亲测)
<template>
<div class="publish">
<!-- 下载按钮 -->
<a id="downLoadLink" style="display: none;"></a>
<video ref="video"></video>
<!-- 视频录制或暂停 -->
<div @click="recordOrStop">视频录制</div>
</div>
</template>
<script>
export default {
data() {
return {
mediaStreamTrack: {}, // 退出时关闭摄像头
video_stream: '', // 视频stream
recordedBlobs: [], // 视频音频 blobs
isRecord: false, // 视频是否正在录制
};
},
mounted() {
// 进入页面 调用摄像头
this.getCamera();
},
methods: {
// 调用打开摄像头功能
getCamera() {
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
navigator.mediaDevices
.getUserMedia({
video: true,
})
.then((stream) => {
// 摄像头开启成功
this.mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[0];
this.video_stream = stream;
this.$refs.video.srcObject = stream;
this.$refs.video.play();
})
.catch(err => {
console.log(err);
});
},
// 录制或暂停
recordOrStop() {
if (this.isRecord) {
this.stop();
} else {
this.record();
}
},
// 视频录制
record() {
console.log('record');
this.isRecord = !this.isRecord;
let mediaRecorder;
let options;
this.recordedBlobs = [];
if (typeof MediaRecorder.isTypeSupported === 'function') {
// 根据浏览器来设置编码参数
if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
options = {
MimeType: 'video/webm;codecs=h264',
};
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) {
options = {
MimeType: 'video/webm;codecs=h264',
};
} else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
options = {
MimeType: 'video/webm;codecs=vp8',
};
}
mediaRecorder = new MediaRecorder(this.video_stream, options);
} else {
// console.log('isTypeSupported is not supported, using default codecs for browser');
console.log('当前不支持isTypeSupported,使用浏览器的默认编解码器');
mediaRecorder = new MediaRecorder(this.video_stream);
}
mediaRecorder.start();
// 视频录制监听事件
mediaRecorder.ondataavailable = e => {
console.log(e);
// 录制的视频数据有效
if (e.data && e.data.size > 0) {
this.recordedBlobs.push(e.data);
}
};
// 停止录像后增加下载视频功能,将视频流转为mp4格式
mediaRecorder.onstop = () => {
const blob = new Blob(this.recordedBlobs, { type: 'video/mp4' });
this.recordedBlobs = [];
// 将视频链接转换完可以用于在浏览器上预览的本地视频
const videoUrl = window.URL.createObjectURL(blob);
// 设置下载链接
document.getElementById('downLoadLink').href = videoUrl;
// 设置下载mp4格式视频
document.getElementById('downLoadLink').download = 'media.mp4';
document.getElementById('downLoadLink').innerHTML = 'DownLoad video file';
// 生成随机数字
const rand = Math.floor((Math.random() * 1000000));
// 生成视频名
const name = `video${rand}.mp4`;
// setAttribute() 方法添加指定的属性,并为其赋指定的值
document.getElementById('downLoadLink').setAttribute('download', name);
document.getElementById('downLoadLink').setAttribute('name', name);
// 0.5s后自动下载视频
setTimeout(() => {
document.getElementById('downLoadLink').click();
}, 500);
};
},
// 停止录制
stop() {
this.isRecord = !this.isRecord;
if (!this.$refs.video.srcObject) return;
const stream = this.$refs.video.srcObject;
const tracks = stream.getTracks();
// 关闭摄像头和音频
tracks.forEach(track => {
track.stop();
});
},
},
};
</script>
<style lang="less" scoped>
.publish {
color: #fff;
video {
width: 100%;
height: 100vh;
}
div {
position: absolute;
left: calc(50% - 80px);
bottom: 0;
height: 40px;
width: 160px;
font-size: 14px;
border-radius: 10px;
line-height: 40px;
background-color: rgb(25, 179, 179);
text-align: center;
}
}
</style>
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳