js调用摄像头拍摄视频

131次阅读
没有评论

简单实现显示摄像头画面、拍摄视频、播放视频、导出视频,访问 浏览器录制视频demo 可以查看最终效果。

代码实现
HTML 放几个 button 和 video:

 

<!--Mr. Ma's Blog www.misterma.com-->
<button type="button" id="start-camera-btn">打开摄像头</button>
<button type="button" id="start-btn">开始录像</button>
<button type="button" id="stop-btn">停止录像</button>
<button type="button" id="play-btn">播放视频</button>
<button type="button" id="export-btn">导出视频</button>
<video width="720" height="360" controls></video>

video 主要用来预览摄像头画面和播放拍摄的视频。

下面的 JavaScript 因为注释比较多,看上去会有点长,但比较容易理解:

const startCameraBtn = document.querySelector('#start-camera-btn'); // 打开摄像头按钮
const startBtn = document.querySelector('#start-btn'); // 开始录像按钮
const stopBtn = document.querySelector('#stop-btn'); // 停止录像按钮
const playBtn = document.querySelector('#play-btn'); // 播放视频按钮
const exportBtn = document.querySelector('#export-btn'); // 导出视频按钮
const videoEl = document.querySelector('video'); // 视频播放元素
let videoData = []; // 存放视频数据
let cameraStream = null; // 存放媒体流
let mediaRecorder = null; // 存放媒体录制对象

// 打开摄像头按钮点击
startCameraBtn.addEventListener('click', () => {
// 申请视频和音频的参数
const constraints = {
audio: true,
video: {
width: 720,
height: 360
}
};
// 申请摄像头和麦克风权限
navigator.mediaDevices.getUserMedia(constraints).then(stream => {
cameraStream = stream;
// 禁用 video 的控制组件
videoEl.controls = false;
// 把媒体流传给 video 的 srcObject
videoEl.srcObject = cameraStream;
// 播放画面和声音
videoEl.play();
}).catch(info => {
alert('错误' + info);
});
});

// 开始录像按钮点击
startBtn.addEventListener('click', () => {
// 创建媒体录制
mediaRecorder = new MediaRecorder(cameraStream, {mimeType: 'video/webm'});
// 开始录制
mediaRecorder.start();

// 处理视频数据
mediaRecorder.addEventListener('dataavailable', ev => {
videoData.push(ev.data);
});

// 录制停止事件
mediaRecorder.addEventListener('stop', () => {
videoData = new Blob(videoData);
});
});

// 停止录像按钮点击
stopBtn.addEventListener('click', () => {
mediaRecorder.stop();
});

// 播放视频点击
playBtn.addEventListener('click', () => {
if (videoData === null) return false;
// 清除 video 的媒体流
videoEl.srcObject = null;
// 把视频数据转为 URL 传给 video 的 src
videoEl.src = URL.createObjectURL(videoData);
// 播放视频
videoEl.play();
// 启用 video 的控制组件
videoEl.controls = true;
// 删除媒体流
cameraStream = null;
});

// 导出视频按钮点击
exportBtn.addEventListener('click', () => {
if (videoData === null) return false;
const link = document.createElement('a');
link.href = URL.createObjectURL(videoData);
link.download = 'video.webm';
link.click();
});

上面的代码只是简单演示,没有做重复点击之类的判断。

详细说明
还是分几步写:

1、显示摄像头画面
使用 navigator.mediaDevices.getUserMedia 请求媒体输入许可,需要传入一个参数来设置媒体类型,我用的参数如下:

const constraints = {
  audio: true,
  video: {
    width: 720,
    height: 360
  }
};

上面的参数是同时申请视频和音频输入设备,视频使用的尺寸是 720*360。

用户授权完成后会返回一个 Promise,成功 then 会返回一个媒体流,失败 catch 会返回错误信息。

把返回的媒体流传给 video 的 srcObject ,video 就可以显示摄像头画面了,同时也能播放麦克风声音。

2、录制视频
有了媒体流就可以创建 MediaRecorder 媒体录制接口,第一个参数 MediaStream 是媒体流,可以使用申请设备权限返回的媒体流,第二个参数是录制选项,我的录制选项是 {mimeType: ‘video/webm’} ,使用 webm 格式来录制视频。webm 是 Google 的视频格式,Chromium 系的浏览器一般都支持,Firefox 和 Safari 不一定支持,可能需要把 mimeType 设置为 video/mp4 。

使用 MediaRecorder 的 start 方法开始录制,start 方法也可以传入一个 timeslice 参数,timeslice 参数可以设置一个毫秒值来把视频数据分割成多个数据块。

MediaRecorder 的 dataavailable 事件会在停止录制时触发,如果在 start 中设置了 timeslice 的话,每个 timeslice 周期结束也会触发。dataavailable 事件会返回一个 event ,使用 event.data 可以获取视频数据。

MediaRecorder 的 stop 方法可以停止录制,停止录制也会触发 MediaRecorder 的 stop 事件,停止录制后我使用 Blob 把视频数据转为了 Blob 数据。

3、播放视频
我用来播放视频的 video 元素和显示摄像头画面的是同一个,把 video 的 srcObject 设置为 null 可以停止播放摄像头画面。使用 URL.createObjectURL 把 Blob 视频数据转换为 DataURL 传给 video 的 src ,调用 video 的 play 方法就可以自动播放视频了。

我使用了 video 的 controls 控制组件来控制视频播放,给 video 加入 controls 属性,video 就会包含基本的播放控制功能,不需要手动编写播放控制。在 video 显示摄像头画面的时候我会禁用 controls 组件,在 video 需要播放视频的时候启用 controls 组件。

4、导出视频
使用 document.createElement 创建一个链接(不需要插入到页面)
使用 URL.createObjectURL 把 Blob 视频数据转为 DataURL 传给链接的 href
通过链接的 download 属性来设置文件名
调用链接的 click 来触发链接的点击事件
如果需要把视频上传到服务器,可以把视频 Blob 数据添加到 FormData 上传。

 

5、老规矩,还是贴一下完整代码,可以直接复制粘贴使用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div style="width: 600px;margin-top: 100px;margin-left: 200px;background-color: #F0F0F0;padding:10px 20px">
    <button type="button" id="start-camera-btn">打开摄像头</button> <button type="button" id="start-btn">开始录像</button> <button type="button" id="stop-btn">停止录像</button> <button type="button" id="play-btn">播放视频</button> <button type="button" id="export-btn">导出视频</button> <video width="720" height="360" controls></video>
</div>
</body>
<script>
    const startCameraBtn = document.querySelector('#start-camera-btn'); // 打开摄像头按钮
    const startBtn = document.querySelector('#start-btn'); // 开始录像按钮
    const stopBtn = document.querySelector('#stop-btn'); // 停止录像按钮
    const playBtn = document.querySelector('#play-btn'); // 播放视频按钮
    const exportBtn = document.querySelector('#export-btn'); // 导出视频按钮
    const videoEl = document.querySelector('video'); // 视频播放元素
    let videoData = []; // 存放视频数据
    let cameraStream = null; // 存放媒体流
    let mediaRecorder = null; // 存放媒体录制对象

    // 打开摄像头按钮点击
    startCameraBtn.addEventListener('click', () => {
// 申请视频和音频的参数
        const constraints = {
            audio: true,
            video: {
                width: 720,
                height: 360
            }
        };
// 申请摄像头和麦克风权限
        navigator.mediaDevices.getUserMedia(constraints).then(stream => {
            cameraStream = stream;
// 禁用 video 的控制组件
            videoEl.controls = false;
// 把媒体流传给 video 的 srcObject
            videoEl.srcObject = cameraStream;
// 播放画面和声音
            videoEl.play();
        }).catch(info => {
            alert('错误' + info);
        });
    });

    // 开始录像按钮点击
    startBtn.addEventListener('click', () => {
// 创建媒体录制
        mediaRecorder = new MediaRecorder(cameraStream, {mimeType: 'video/webm'});
// 开始录制
        mediaRecorder.start();

// 处理视频数据
        mediaRecorder.addEventListener('dataavailable', ev => {
            videoData.push(ev.data);
        });

// 录制停止事件
        mediaRecorder.addEventListener('stop', () => {
            videoData = new Blob(videoData);
        });
    });

    // 停止录像按钮点击
    stopBtn.addEventListener('click', () => {
        mediaRecorder.stop();
    });

    // 播放视频点击
    playBtn.addEventListener('click', () => {
        if (videoData === null) return false;
// 清除 video 的媒体流
        videoEl.srcObject = null;
// 把视频数据转为 URL 传给 video 的 src
        videoEl.src = URL.createObjectURL(videoData);
// 播放视频
        videoEl.play();
// 启用 video 的控制组件
        videoEl.controls = true;
// 删除媒体流
        cameraStream = null;
    });

    // 导出视频按钮点击
    exportBtn.addEventListener('click', () => {
        if (videoData === null) return false;
        const link = document.createElement('a');
        link.href = URL.createObjectURL(videoData);
        link.download = 'video.webm';
        link.click();
    });
</script>
</html>

6、效果图

js调用摄像头拍摄视频

正文完
 
评论(没有评论)