视频检测和音频检测
最近做音视频开发有涉及到这些功能,在此记录一下。
1. 视频检测
包括获取摄像头、切换摄像头、打开/关闭摄像头以及截图功能,界面效果如下,代码使用的是Vue框架。
1.1 获取设备
首先利用webRTC mediaDevices这个接口的enumerateDevices()方法获取所有的设备列表,然后将其按摄像头、麦克风、扬声器三种类型存储到列表中,存储时将设备的label作为设备标识并且要将每个设备的deviceId存储到列表,方便后边的摄像头切换。
// 获取设备
getMedia (context) {
return navigator.mediaDevices.enumerateDevices().then((devices) => {
// this.cameraList = [];
console.log(devices);
devices.forEach((device) => {
if (device.kind == "videoinput") {
context.commit("setCameraList", {
label: device.label,
id: device.deviceId,
});
context.commit("updateDefaultCamera", state.cameraList[0].id);
} else if (device.kind == "audiooutput") {
context.commit("setMicroPhoneList", {
label: device.label,
id: device.deviceId,
});
context.commit("updateDefaultMicroPhone", state.microPhoneList[0].id);
} else if (device.kind == "audioinput") {
context.commit("setAudioList", {
label: device.label,
id: device.deviceId,
});
context.commit("updateDefaultAudio", state.audioList[0].id);
}
});
});
},
1.2 打开摄像头
获取到摄像头设备后,就可以利用mediaDevices接口的getUserMedia()方法打开摄像头。因为我这里已经将设备绑定的deviceId作为参数传给了video,再借助vue的v-model双向绑定,就可以实现切换功能了,所以我前面强调一定要将deviceId存到设备列表上,这是重点。
// 打开摄像头
callCamera () {
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop();
});
}
navigator.mediaDevices.getUserMedia({
// video: true
video: {
deviceId: this.$store.state.defaultCamera ?
{ exact: this.$store.state.defaultCamera } : undefined
}
}).then(stream => {
// 把媒体流赋值给 video 元素的 srcObj 属性,我们就能从屏幕上看到视频了
this.$refs['video'].srcObject = stream
// 实时拍照效果
this.$refs['video'].play()
}).catch(error => {
console.log(error);
this.$message.error('摄像头开启失败,请检查摄像头是否可用!');
})
},
1.3 关闭摄像头
关闭摄像头只要停止当前流的轨道即可。
// 关闭摄像头
closeCamera () {
if (!this.$refs['video']) {
return
} else {
if (this.$refs['video'].srcObject) {
let stream = this.$refs['video'].srcObject
let tracks = stream.getTracks()
tracks.forEach(track => {
track.stop()
})
this.$refs['video'].srcObject = null
}
}
},
1.4 截图
虽然这里没有做这个功能,但是开启摄像头之后还可以实现拍照并保存图片功能
// 拍照
photograph () {
// 图片容器
let ctx = this.$refs['canvas'].getContext('2d')
// 把当前视频帧内容渲染到canvas上
ctx.drawImage(this.$refs['video'], 0, 0, 640, 480)
// 转base64格式、图片格式转换、图片质量压缩---支持两种格式image/jpeg+image/png
let imgBase64 = this.$refs['canvas'].toDataURL('image/jpeg', 0.7)
/**------------到这里为止,就拿到了base64位置的地址,后面是下载功能----------*/
// 由字节转换为KB 判断大小
let str = imgBase64.replace('data:image/jpeg;base64,', '')
let strLength = str.length
// 图片尺寸 用于判断
let fileLength = parseInt(strLength - (strLength / 8) * 2)
let size = (fileLength / 1024).toFixed(2)
// 上传拍照信息 调用接口上传图片 .........
console.log(size)
// 保存到本地
let ADOM = document.createElement('a')
ADOM.href = this.headImgSrc
ADOM.download = new Date().getTime() + '.jpeg'
ADOM.click()
},
2. 音频检测
选择扬声器和麦克风设备,对它们进行输出等级(实时音量)检测及音量调节,界面如下:
2.1 切换扬声器
首先利用setSinkId()方法切换要检测的扬声器,重点也是我前面提到的要把当前选中设备的deviceId作为参数。
// 切换扬声器
changeMicro () {
console.log("change");
this.$refs['audio'].setSinkId(this.$store.state.defaultMicroPhone)
.then(() => {
console.log(this.$store.state.defaultMicroPhone);
}).catch(error => {
console.log(error);
})
},
2.2 检测扬声器
首先同摄像头一样先获取到设备,然后选定设备开始检测。我这里是检测一段音频文件
// 检测扬声器
testMicro () {
if ('检测' === this.beginTestMicro) {
this.$refs['audio'].play();
// 定时获取音量
var _that = this;
this.audioVolume = _that.$refs['audio'].volume
// 将本地文件转化为媒体流
let stream = _that.$refs['audio'].captureStream();
window.AudioContext = window.AudioContext || window.webkitAudioContext;
window.audioContext = new AudioContext();
// 根据第二个参数判断是要获取扬声器还是麦克风的输出等级
this.handleSuccess(stream, 'micro')
this.beginTestMicro = '停止检测'
} else if ('停止检测' == this.beginTestMicro) {
this.$refs['audio'].pause()
this.audioVolume = 0;
this.beginTestMicro = '检测';
}
},
handleSuccess是WebRTC上定义的检测麦克风的函数,这里同样可以用来检测扬声器。
handleSuccess (stream, type) {
var _that = this
console.log(stream);
// 成功调用麦克风后,媒体输入会产生一个MediaStream,其中包含了请求的媒体类型的轨道,将此轨道保存
window.stream = stream;
const soundMeter = window.soundMeter = new SoundMeter(window.audioContext);
soundMeter.connectToSource(stream, function (e) {
if (e) {
alert(e);
return;
}
// 组件卸载需要清除定时器,使用useRef()
_that.meterRefresh = setInterval(() => {
// 设置展示数据,就是取得音量
if (type == 'audio') {
_that.volume =
soundMeter.instant.toFixed(2);
} else if (type == 'micro') {
_that.microLevel =
soundMeter.instant.toFixed(2);
}
}, 200);
});
},
2.3 设置扬声器音量
因为这里是提前准备好的音频,只要直接设置audio元素的volume即可。
// 修改扬声器音量
changeMicroVolume (index) {
this.$refs['audio'].volume = index / 100;
this.microVolume = index;
},
2.4 切换麦克风
麦克风的切换同摄像头。
2.5 检测麦克风
麦克风的输出等级检测类似扬声器,只是麦克风是检测我们开启麦克风后产生的实时流。
testAudio () {
if ('检测' == this.beginTestVolume) {
this.beginTestVolume = '停止检测'
try {
// 跨浏览器
window.AudioContext = window.AudioContext || window.webkitAudioContext;
// AudioContext:音频上下文,负责音频的处理和解码
window.audioContext = new AudioContext();
} catch (e) {
alert('Web Audio API not supported.');
}
// 调用开启麦克风
navigator.mediaDevices
.getUserMedia({
audio: {
deviceId: this.$store.state.defaultAudio ?
{ exact: this.$store.state.defaultAudio } : undefined
},
video: false
})
.then(stream => this.handleSuccess(stream, 'audio'))
.catch(this.handleError);
} else if ('停止检测' == this.beginTestVolume) {
this.beginTestVolume = '检测'
// 获取到上面的媒体轨道信息数组 遍历关闭
window.stream.getTracks().forEach(track => track.stop());
window.soundMeter.stop();
// 组件卸载需要清除定时器
clearInterval(this.meterRefresh);
this.volume = '';
}
},