前端使用navigator.mediaDevices.getUserMedia和window.MediaRecorder实现调用摄像头录制视屏
一、navigator.mediaDevices.getUserMedia
MediaDevices.getUserMedia()会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其它轨道类型。
它返回一个 Promise
对象,成功后会resolve
回调一个 MediaStream
对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promise
会reject
回调一个 PermissionDeniedError
或者 NotFoundError
。
navigator.mediaDevices.getUserMedia详细的使用方法以及API可以去看官方文档
二、window.MediaRecorder
MediaRecorder()
构造函数会创建一个对指定的 MediaStream
进行录制的 MediaRecorder
对象。
这里的MediaStream就是上面resolve返回的那个MediaStream。
语法:
var mediaRecorder = new MediaRecorder(stream[, options]);
stream:
MediaStream
将要录制的流. 它可以是来自于使用 navigator.mediaDevices.getUserMedia()
创建的流或者来自于,以及DOM元素.
option(可选):
一个对象,包含一下属性:
mimeType
: 为新构建的MediaRecorder
指定录制容器的MIME类型. 在应用中通过调用MediaRecorder.isTypeSupported()
来检查浏览器是否支持此种mimeType
.audioBitsPerSecond
: 指定音频的比特率.videoBitsPerSecond
: 指定视频的比特率.bitsPerSecond
: 指定音频和视频的比特率. 此属性可以用来指定上面两个属性. 如果上面两个属性只有其中之一和此属性被指定, 则此属性可以用于设定另外一个属性.
window.MediaRecorder详细使用方法可以去看官方文档
三、简单实现调用摄像头录制视屏
使用react框架实现,调用的是原生方法,其他框架的写法都差不多。
页面结构:
<div>
{/* 这个video标签录制时看到实时画面使用 */}
<video src="" ref='video' className={styles.video}></video>
<button onClick={this.clickStart.bind(this)}>开始</button>
<button onClick={this.clickEnd.bind(this)}>停止</button>
{
this.state.chunkURL ? <a href={this.state.chunkURL} download='test.webm'>点击下载</a> : ''
}
{/* 这个video标签是录制完后把录制之后的数据处理为二进制流后进行展示使用 */}
<video src={this.state.chunkURL} className={styles.video} ref='newvideo'></video>
</div>
1、在页面加载的时候需要把使用媒体输入和创建录制视屏的弄好。
下面代码是需要在页面加载的时候完成。
init() {
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(
(stream) => {
this.recorder = new window.MediaRecorder(stream)
this.setState({
stream: stream
})
},
(error) => {
alert("出错,请确保已允许浏览器获取音视频权限");
}
);
}
2、点击开始需要干的事情
(1)把第一个video标签的srcObject属性和navigator.mediaDevices.getUserMedia成功返回的stream关联上
(2)video的muted属性是是否静音,值是布尔值,true为静音
(3)让视屏播放起来
(4)让recorder开始录制
(5)给recorder绑定上ondataavailable和onstop的回调 ondataavailable:当有又用的数据的时候触发,onstop:停止录制当然时候触发
// 给record绑定事件的回调
bindEvents() {
this.recorder.ondataavailable = (e) => {
this.setState({
chunk: e.data
})
}
this.recorder.onstop = () => {
let blob = new Blob([this.state.chunk], { type: 'video/webm' })
let videoStream = URL.createObjectURL(blob);
this.setState({ chunkURL: videoStream })
setTimeout(()=>{
console.log(this.state.chunkURL);
},5000)
this.refs.newvideo.play()
}
}
// 点击开始
clickStart() {
this.onPreview()
this.onStart()
this.bindEvents()
}
onPreview() {
this.refs.video.srcObject = this.state.stream
this.refs.video.muted = true
this.refs.video.play();
}
onStart() {
this.recorder.start();
}
3、点击结束
点击结束按钮调用record的stop事件停止录制,同时将第一个video标签暂停,不暂停也不影响,只有一直有摄像头拍到的实时画面但是不会录制。
clickEnd() {
this.recorder.stop()
this.refs.video.pause()
}
完整代码
import React from 'react'
import styles from './index.less'
class VideoDemo extends React.Component {
constructor(prop) {
super(prop)
this.state = {
recorder: null,
stream: null,
chunk: null,
chunkURL: null
}
this.recorder = null
}
render() {
return (
<div>
{/* 这个video标签录制时看到实时画面使用 */}
<video src="" ref='video' className={styles.video}></video>
<button onClick={this.clickStart.bind(this)}>开始</button>
<button onClick={this.clickEnd.bind(this)}>停止</button>
{
this.state.chunkURL ? <a href={this.state.chunkURL} download='test.webm'>点击下载</a> : ''
}
{/* 这个video标签是录制完后把录制之后的数据处理为二进制流后进行展示使用 */}
<video src={this.state.chunkURL} className={styles.video} ref='newvideo'></video>
</div>
)
}
init() {
navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(
(stream) => {
this.recorder = new window.MediaRecorder(stream)
this.setState({
stream: stream
})
},
(error) => {
alert("出错,请确保已允许浏览器获取音视频权限");
}
);
}
// 给record绑定事件的回调
bindEvents() {
this.recorder.ondataavailable = (e) => {
this.setState({
chunk: e.data
})
}
this.recorder.onstop = () => {
let blob = new Blob([this.state.chunk], { type: 'video/webm' })
let videoStream = URL.createObjectURL(blob);
this.setState({ chunkURL: videoStream })
setTimeout(()=>{
console.log(this.state.chunkURL);
},5000)
this.refs.newvideo.play()
}
}
// 点击开始
clickStart() {
this.onPreview()
this.onStart()
this.bindEvents()
}
onPreview() {
this.refs.video.srcObject = this.state.stream
this.refs.video.muted = true
this.refs.video.play();
}
onStart() {
this.recorder.start();
}
clickEnd() {
this.recorder.stop()
this.refs.video.pause()
}
componentDidMount() {
this.init()
}
}
export default VideoDemo
less样式代码
.video{
width: 100vw;
height: 50vh;
}
总结
1、如果只想录制声音或是其他什么的只需要改init方法里面getUserMedia方法里的参数。
()
}
componentDidMount() {
this.init()
}
}
export default VideoDemo
less样式代码
.video{
width: 100vw;
height: 50vh;
}
## 总结
1、如果只想录制声音或是其他什么的只需要改init方法里面getUserMedia方法里的参数。
2、本来想实现a标签下载的,但是不知道为什么下载下来的视屏是黑色的没有画面。该问题还未解决,解决了再来更新。