vuepc电脑可以获取设备吗

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vuepc电脑可以获取设备吗相关的知识,希望对你有一定的参考价值。

VUE2实现录像(PC端)可拍照 下载 预览 选取指定摄像头和麦克风设备 源代码可直接使用 原创
2022-10-16 17:57:44

嗯呐FT 

码龄1年

关注
2022.10月份 谷歌是最新版本 使用vue2写



下面的这些代码可以在谷歌浏览器的本地(localhost)和https环境下执行。中间有大量的注释可查看,基本上看一遍就懂,前面的坑我基本都踩过了。

如果是http环境的话,我下面这些代码是执行不了的,因为我做了获取指定设备的功能,如果要http环境中使用,需要把获取指定设备的相关代码删掉才能用,而且需要去谷歌的这个地址配置一下才能用,最下面我会介绍怎么在http环境中用。

功能如下:

1.可获取多个摄像头设备并选择其一进行录制

2.录制的过程中拔掉摄像头监听结束录制

3.可在录制中进行拍照生成png图片 可预览 可下载

4.录制完成会生成一个有声音和画面的webm格式视频 可在线预览下载

5.录制的过程中计时(最小误差)

界面展示(界面我就做个小Demo 没有过多去弄好看点 重要是script部分)



先上代码 -- html部分

<template>
<div class="publish">
<div class="box">
<div class="videoPart">
<div class="videoRecord" @mouseenter="hoverVideo(0)" @mouseleave="hoverVideo(1)">
<video id="videoCamera" :width="videoWidth" :height="videoHeight" autoPlay></video>
<div class="hoverVideoOutside" v-if="ifHoverVideo && ifStartRecord" >
<div class="hoverVideoInside">
<div class="hoverVideoInsideInside">
<div class="hoverVideoBtn"><div class="hoverVideoBtnInside"></div></div>
<span>recordHMSTime</span>
</div>
</div>
</div>
</div>
<canvas id="canvasCamera" class="canvas" :width="videoWidth" :height="videoHeight"></canvas>
<video v-if="showVideo" :src="videoSrc" autoplay controls></video>
<img v-if="showImg" class="imgClass" :src="imgSrc" alt="">
</div>
<div>
<el-select v-model="deviceId" placeholder="请选择摄像头" @change="selectVideoChange" @focus="findVideoDevice" :disabled="ifStartRecord">
<el-option
v-for="item in deviceArr"
:key="item.deviceId"
:label="item.label"
:value="item.deviceId">
</el-option>
</el-select>
<el-button v-if="!ifStartRecord" @click="startRecord" icon="el-icon-video-camera" size="small">开始录制</el-button>
<el-button v-else @click="stopRecord" icon="el-icon-switch-button" size="small">结束录制</el-button>
<el-button @click="photographBtn" icon="el-icon-camera" size="small">拍照</el-button>
</div>
<vxe-table
border
resizable
show-overflow
ref="xTable"
height="500"
:row-config="isHover: true"
:data="tableData">
<vxe-column type="seq" width="60"></vxe-column>
<vxe-column field="name" title="Name"></vxe-column>
<vxe-column title="操作" width="200" show-overflow>
<template #default=" row ">
<vxe-button type="text" icon="vxe-icon-edit" @click="preview(row)">预览</vxe-button>
<vxe-button type="text" icon="vxe-icon-edit" @click="download(row)">下载</vxe-button>
</template>
</vxe-column>
</vxe-table>
</div>
</div>
</template>
CSS代码

<style scoped>
.canvas
opacity: 0!important;

.videoPart
position: relative;
display: flex;
align-items: center;

.hoverVideoOutside
position: absolute;
top: 0px;
left: 0px;
width: 500px;
height: 300px;
background:linear-gradient(#000,transparent 20%);
z-index: 999;

.hoverVideoInside
position: relative;
width: 100%;
height: 100%;

.hoverVideoInsideInside
position: absolute;
top: 10px;
left: 380px;
padding: 2px;
display: flex;
justify-content: center;
align-items: center;

.hoverVideoBtn
width: 30px;
height: 30px;
border-radius: 50%;
border: 2px solid red;
padding: 3px;
box-sizing: border-box;
margin-right: 4px;

.hoverVideoBtnInside
background: red;
width: 20px;
height: 20px;
border-radius: 50%;
box-sizing: 50%;

span
color: #fff;

.videoRecord
position: relative;

.imgClass
width: 500px;
height: 300px;


</style>
逻辑部分

<script>
export default
name: 'HelloWorld',
data()
return
ifOpenCamera: false,//控制摄像头开关
ifStartRecord:false, //是否开始录制
thisVideo: null,
thisContext: null, //canvas
thisCanvas: null,
videoWidth: 500,
videoHeight: 300,
videoCecorded: [], //接受的数据流
mediaRecorderData: ,
videoSrc:'', //录制完的视频预览
imgSrc:'',//录制完预览的图片地址
deviceArr:[],//获取该电脑的摄像头
deviceId:'', //选择哪个摄像头
tableData:[], //录制完 制作表格数据
showVideo:false, //录制完预览视频
showImg:false,//录制完预览图片
recordTime:0, //监听录像的时间
recordHMSTime:'00:00:00', //监听录像的时间
ifHoverVideo:false, //监听是否鼠标在视频的上面 显示录制时间
timer:null, //每一秒执行一次计算录像的时间 这个是有误差的
startTime:'', //记录开始录制的时间戳
stream:null,

,

created()
this.initDevice();
,
methods:
initDevice()
this.$nextTick(() =>
this.videoCecorded = []
this.mediaRecorderData = null
this.thisCanvas = document.getElementById('canvasCamera');
this.thisContext = this.thisCanvas.getContext('2d');
this.thisVideo = document.getElementById('videoCamera');
// 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
console.log('navigator.mediaDevices', navigator.mediaDevices)
if (navigator.mediaDevices === undefined)
navigator.mediaDevices =
this.dialogVisible = !this.dialogVisible;
console.log('http环境下没开那个谷歌权限 所以有点问题 得弹出提示弹窗 如果是本地或者https环境就基本不会走到这里')
this.$message(
message: '去谷歌浏览器配置网址',
type: 'error'
)

// 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
// 使用getUserMedia,因为它会覆盖现有的属性。
// 这里,如果缺少getUserMedia属性,就添加它。
if (navigator.mediaDevices.getUserMedia === undefined)
navigator.mediaDevices.getUserMedia = function (constraints)
// 首先获取现存的getUserMedia(如果存在)
let getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia;
// 有些浏览器不支持,会返回错误信息
// 保持接口一致
if (!getUserMedia)
return Promise.reject(new Error('getUserMedia is not implemented in this browser'))

// 否则,使用Promise将调用包装到旧的navigator.getUserMedia
return new Promise(function (resolve, reject)
getUserMedia.call(navigator, constraints, resolve, reject)
)


this.findVideoDevice()
)
,
// 每次点开下拉框的时候都要去获取现在有多少个设备 以防在打开这个网站之后把摄像头拔了等情况
async findVideoDevice()
this.deviceId = ''
this.deviceArr = []
const _this = this
try
// 获取你电脑中有什么设备
let deviceArr = await navigator.mediaDevices.enumerateDevices();
if(this.deviceArr.length == 0)
this.$message(
message: '没有摄像头设备',
type: 'error'
)
this.deviceArr = []
return

console.log('设备',deviceArr)
deviceArr.forEach(item=>
if(item.kind == 'videoinput')
this.deviceArr.push(item) //获取你电脑中有多少个摄像头设备

)
catch(error)
console.log(error)
this.deviceArr = []

,
// 选择完是哪个摄像头以后执行的方法
selectVideoChange()
this.$nextTick(() =>
const _this = this;
const constraints =
audio: true,
video:
width: _this.videoWidth,
height: _this.videoHeight,
transform: 'scaleX(-1)',
deviceId:exact:this.deviceId
,
;
navigator.mediaDevices.getUserMedia(constraints).then(async(stream)=>
// 旧的浏览器可能没有srcObject
if ('srcObject' in _this.thisVideo)
_this.thisVideo.srcObject = stream
else
// 避免在新的浏览器中使用它,因为它正在被弃用。
_this.thisVideo.src = window.URL && window.URL.createObjectURL(stream)

_this.thisVideo.onloadedmetadata = function (e)
_this.thisVideo.play()

_this.ifOpenCamera = true
).catch(err =>
this.errReponse(err)
);
);
,
// 开始录制
startRecord()
if(this.deviceId == '')
this.$message(
message: '请选择摄像头',
type: 'error'
)
return

const _this = this
this.mediaRecorderData = null
this.videoCecorded = []
this.$nextTick(()=>
const constraints =
audio: true,
video:
width: this.videoWidth,
height: this.videoHeight,
transform: 'scaleX(-1)',
deviceId:exact:this.deviceId //选取指定的设备来录制
,
;
//必须在model中render后才可获取到dom节点,直接获取无法获取到model中的dom节点
navigator.mediaDevices.getUserMedia(constraints).then(function (stream)
_this.stream = stream
// 这个要重写一次
// 我插第三方的视频录像设备的情况下 点击录像 然后把设备拔出来 这个时候画面是黑色的
// 如果没有重写下面的方法 插进设备后 点击录像 画面依然是黑色的 但是能录像 只是界面上不显示
if ('srcObject' in _this.thisVideo)
_this.thisVideo.srcObject = stream
else
// 避免在新的浏览器中使用它,因为它正在被弃用。
_this.thisVideo.src = window.URL && window.URL.createObjectURL(stream)

_this.thisVideo.onloadedmetadata = function (e)
_this.ifOpenCamera = true
_this.thisVideo.play()

_this.startRecording(stream);//调用录制控件方法,触发开始录制
).catch(err =>
// 点录制之前断开设备连接 但选择框已经选了设备 就会触发这个err
this.errReponse(err)
);
)
,
//拍照按钮
photographBtn()
//先判断是否开启了摄像头
if(!this.ifOpenCamera)
this.$message(
message: '摄像头都还没开呢 傻猪猪',
type: 'error'
)
return

// 点击,canvas画图
this.thisContext.drawImage(this.thisVideo, 0, 0, this.videoWidth, this.videoHeight);
// 如果图片尺寸不想 500 300 那就写下面这个
// this.thisContext.drawImage(this.thisVideo, 0, 0, this.videoWidth, this.videoHeight,0,0,1000, 600);
const fileName = (new Date).toISOString().replace(/:|\./g,'-')
const a = this.thisCanvas.toDataURL('image/png')
const file = this.dataURLtoFile(a,fileName + 'png')
this.tableData.push(
id:2,
name:fileName + 'png',
url:this.thisCanvas.toDataURL('image/png'),
type:'png'
)
,
//停止录制
stopRecord()
if (this.thisVideo && this.thisVideo !== null)
this.mediaRecorderData.stop(); //结束录制

,
// 开始录制中
startRecording(stream)
console.log('stream 在开始的时候的',stream)
let _this = this
this.mediaRecorderData = new MediaRecorder(stream,
mimeType: 'video/webm;codecs=vp8,opus' //不加这个codecs=vp8,opus有时候下载下来之后看几秒就没了 残缺的视频
);
this.mediaRecorderData.addEventListener("dataavailable", (e) =>
if (e.data.size > 0)
_this.videoCecorded.push(e.data);//视频录制视频流数据
;
);

this.mediaRecorderData.addEventListener("stop", () =>
console.log("结束录制");
_this.updataVideo();//上传实时录制的视频
_this.ifStartRecord = false
_this.recordTime = 0
_this.recordHMSTime = '00:00:00'
clearTimeout(_this.timer)
_this.timer = null
);

this.mediaRecorderData.addEventListener("start", (e) =>
console.log("开始 录制");
_this.ifStartRecord = true
_this.recordTime = 0
_this.startTime = new Date().getTime();
_this.timer = setTimeout(_this.fixed,1000)
);
this.mediaRecorderData.start()
,

// 上传录制视频方法,获取视频地址
updataVideo()
const blob = new Blob(this.videoCecorded,
type: 'video/webm'
);
const fileName = (new Date).toISOString().replace(/:|\./g,'-')
this.tableData.push(
id:2,
type:'webm',
name:fileName + '.webm',
url:URL.createObjectURL(blob)
)
,
// 预览视频 图片
preview(row)
if(row.type == 'png')
this.showImg = true
this.showVideo = false
this.imgSrc = row.url
else if(row.type == 'webm')
this.showVideo = true
this.showImg = false
this.videoSrc = row.url
else
this.$message(
message: '无法预览',
type: 'error'
)

,
download(row)
let aTag = document.createElement('a');//创建一个a标签
aTag.download = row.name;
aTag.href = row.url;
aTag.click();
,
hoverVideo(num)
if(num)
// 移出
this.ifHoverVideo = false
else
// 移入
this.ifHoverVideo = true

,
secondChangeMinute(second)
const hour = parseInt(second / 3600)
const min = parseInt(second / 60)
const se = parseInt(second % 60)
const cHour = hour<10?'0'+hour:hour
const cMin = min<10?'0'+min:min
const cSe = se<10?'0'+se:se
return cHour + ':' + cMin + ':' + cSe
,
fixed()
this.recordTime += 1
this.recordHMSTime = this.secondChangeMinute(this.recordTime)
if(!this.stream.active)
this.stopRecord()

var offset = new Date().getTime() - (this.startTime + this.recordTime * 1000);
var nextTime = 1000 - offset;
if (nextTime < 0) nextTime = 0;
this.timer = setTimeout(this.fixed, nextTime);
,
errReponse(err)
const message = err.message || err
const response =
'permission denied': '浏览器禁止本页面使用摄像头或麦克风,请开启相关的权限',
'requested device not found': '未检测到摄像头'

console.log(response[ message.toLowerCase() ] || '未知错误');
this.$message(
message: response[ message.toLowerCase() ] || '未知错误',
type: 'warning'
)
,
dataURLtoFile: function(dataurl, filename)
let arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--)
u8arr[n] = bstr.charCodeAt(n);

return new File([u8arr], filename, type: mime );
,

// 这个方法是给需要的人看的 演示打开摄像头的方法
async openCamera()
await navigator.mediaDevices.getUserMedia(audio:true,video:true).then(()=>
//我这个时候已经打开摄像头了
).catch(err=>
this.errReponse(err)
)
,
// 这个方法是给需要的人看的 演示关闭摄像头的方法
closeCamera()
this.thisVideo.srcObject.getTracks().forEach(item =>
// 关闭当前所有已打开的设备(你刚刚选择的摄像头设备和你默认的麦克风)
item.stop()
)
,


</script>
问题解答区域:

1.录制的视频只能是webm格式吗?进度条呢?

答:我在写程序的时候发现只能写webm格式,如果是写MP4或者其他类型,视频下载下来是没有办法播放的,可能在移动端就没有问题,我还没有去尝试在移动端做这个功能。webm格式我所知道的有两个弊端,下载下来的时候无法拖动进度条,而且要在指定播放器中才能播放。如果想要解决这个进度条的问题,可以去看这个地址的解决方法。前端 mediaRecorder 录制视频源代码实例,和本地播放器无法定位进度条问题分析和解决_anne都的博客-CSDN博客_mediarecorder 进度条

2.http问题

答:在http环境下是可以录制的,但是我上面的代码运行不了就是了。因为我添加了一个获取用户电脑中设备的功能,该功能在http环境下没有办法获取,可能是浏览器出于安全的问题。如果想要在http环境下录制,可以参考下面的这个地址,我也是百度了很久,看了很多别人的博客才得出的最终代码结果。地址如下:

=>1.JS调用媒体设备失败 --- getUserMedia undefine 问题(各浏览器配置方法)_<!--玄德-->的博客-CSDN博客_浏览器不支持getusermedia

=>2.

PC端调用摄像头录制视频——vue标准写法_前端_森森的博客-CSDN博客_vue调用摄像头录像

=>3.

JS基于页面实现音视频的录制(一)_画虎成鳖的博客-CSDN博客_js录制视频

3.表格不一定要用vxetable,随便用

4.如果还有什么问题再在评论区问吧。。
参考技术A 可以
获取设备的Mac地址可以通过电脑来实现,具体步骤如下:
1.
首先,打开您的电脑,在开始菜单中点击“运行”,然后输入“cmd”,按回车键打开命令提示符窗口。
2.
在命令提示符窗口中,输入“ipconfig/all”,然后按回车键,您将看到有关您的网络设置的详细信息。
3.
在这些信息中,您可以找到您的物理地址,这就是您的Mac地址。
参考技术B 1.可获取多个摄像头设备并选择其一进行录制

2.录制的过程中拔掉摄像头监听结束录制

3.可在录制中进行拍照生成png图片 可预览 可下载

4.录制完成会生成一个有声音和画面的webm格式视频 可在线预览下载

5.录制的过程中计时(最小误差
参考技术C 1.可获取多个摄像头设备并选择其一进行录制 2.录制的过程中拔掉摄像头监听结束录制 3.可在录制中进行拍照生成png图片 可预览 可下载 4.录制

电视盒的airplayserver可以删除吗

右键单击我的电脑-属性-“硬件”标签-设备管理器,在通用串行总线控制器下面找到对应设备-右键,属性-“驱动程序”标签-最下面的卸载。 参考技术A   右键单击我的电脑-属性-“硬件”标签-设备管理器,在通用串行总线控制器下面找到对应设备-右键,属性-“驱动程序”标签-最下面的卸载。
  airplayserver是一种空中游戏服务器。

以上是关于vuepc电脑可以获取设备吗的主要内容,如果未能解决你的问题,请参考以下文章

我正在使用低端笔记本电脑来学习使用 web 和 android 设备的颤振。有啥方法可以加快构建过程吗?

HTML5 或者JS可以获取移动设备信息吗?或者其他非开发语言的方法

开发IOS应用真的一定要买苹果电脑设备吗?

Android手机可以远程控制另一个手机吗

蓝牙BLE如何连接连接多台设备

android 设备如何获取mac地址吗