js实行原生录像

js实行原生录像

公司需要一个js原生的视频录像功能,之前没用做了,写个笔记记录下。

一、获取摄像头

既然要录像,就要获取摄像头权限。那我们就先实现这一步再说。通过参阅一些资料得知,js可以使用navigator.mediaDevices来获取摄像头。





    
    
    
    demo



    
    



在手机运行demo,会发现navigator.mediaDevices总是undefined,原因是navigator.mediaDevices() 只有在以下三种环境中才能获取到:

1、localhost 域
2、开启了 HTTPS 的域
3、使用 file:// 协议打开的本地文件

因为我是用的pc开发,也没有摄像头,手机没发用localhost访问,就用node搭建了一个https服务
a、生成证书文件

1、打开git bash检测openssl是否安装:openssl version -a
2、生成私钥key文件:openssl genrsa -out privatekey.pem 1024
3、通过私钥生成CSR证书签名:openssl req -new -key privatekey.pem -out certrequest.csr
4、通过私钥和证书签名生成证书文件:openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem

b、编写node代码

let https = require('https');
let fs = require('fs');
let express = require('express');

let app = express();
app.use(express.static('./public'));

let options = {
    key: fs.readFileSync('./privatekey.pem'),
    cert: fs.readFileSync('./certificate.pem')
}

let https_server = https.createServer(options, app);
https_server.listen(8089)

对于使用笔记本的同学来说,直接用手机访问localhost就可以了。下面在提供一种在Chrome中使用http访问的方法,在手机端测试下貌似不行,只有在pc上可以。

打开 chrome://flags/#unsafely-treat-insecure-origin-as-secure
将该 flag 切换成 enable 状态
输入框中填写需要开启的域名,譬如 http://example.com",多个以逗号分隔。

但是这是我们并不能正常运行代码,点击开是会得到一条报错:8089/[object%20MediaStream] 404 (Not Found)。将then方法替换为下面的代码就行了

.then(function(stream) {
    // 将摄像头拍到的东西,通过video展现出来
    video.srcObject = stream;
    video.onloadedmetadata = function(e) {
        video.play();
    };
})

二、打开后置摄像头

现在我们能正常调起摄像头了,但是默认打开的是后置摄像头,只需要修改constraints就可以了

//修改constraints
const constraints = {
    video: {
        facingMode: 'environment',
    },
    audio: false,
};

根据需求还需要一个转换摄像头的按钮。整体思路比较简单,当点击按钮是就关闭当前媒体,再重新打开一个相反的摄像头

const change = document.getElementById('change')
// environment:后置 user:前置
let facingMode = "environment"
// 保存媒体流
let currentStream = null
change.addEventListener("click", function() {
    facingMode = facingMode === "user" ? "environment" : "user"
    openCam()
})
// 停止所有的媒体
function stopMediaTracks(stream) {
    stream.getTracks().forEach(track => {
        track.stop();
    });
}
// 修改openCam
function openCam() {
    if (currentStream) stopMediaTracks(currentStream);
    const constraints = {
        video: {
            facingMode: facingMode,
        },
        audio: false,
    };
    navigator.mediaDevices.getUserMedia(constraints)
        .then(function(stream) {
                currentStream = stream
                    ......
            }
        }

三、开始录像

基本的事情我们都做到了,接下来就要录制视屏, 代码实现

let allChunks = [];
// 捕捉canvas的内容,转化为MediaStream对象
const stream2 = canvas.captureStream(60);
// 创建一个录制MediaRecorder 对象
const recorder = new MediaRecorder(stream2, {
    mimeType: 'video/webm;codecs=vp9'
});
//开始录制
function startRecording() {
    // 每10ms记录一次,也就是执行ondataavailable
    recorder.start(10);
}
// 停止录制
function stopAndblobDownload() {
    recorder.stop();
    // 将录制的数据流转化为Blob
    const fullBlob = new Blob(allChunks);
    // 生成一个路径,可上传下载
    const downloadUrl = window.URL.createObjectURL(fullBlob);
}
// 将录制的数据流保存起来
recorder.ondataavailable = e => {
    allChunks.push(
        e.data
    );
}

function openCam() {
    ......
    then(res => {
        navigator.mediaDevices.getUserMedia(constraints)
            .then(function(stream) {
                    ......
                    // 把video写入到canvas中
                    setInterval(() => {
                        context.drawImage(video, 0, 0, 640, 480);
                    }, Math.floor(1000 / 60));
                }
            }
    })
}

以上就基本实现了录制视频功能。

四、思路总结

首先我们得用navigator.mediaDevices.getUserMedia获取摄像头权限,这里注意mediaDevices使用的条件。将getUserMedia的成功回调函数(then)中得到的媒体流,用video呈现,再用canvas(drawImage API)绘制vidoe。转换(captureStream API)canvas为MediaStream对象。通过MediaRecorder对象进行录制。其实captureStream是HTMLMediaElement原型上的方法,所有HTMLMediaElement都能调用,也就是说video能直接转换为MediaStream对象。修改代码:

  //  const stream2 = canvas.captureStream(60); 
  const stream2 = video.captureStream(60);
  ...
  // setInterval(() => {
  //   context.drawImage(stream, 0, 0, 640, 480);
  // }, Math.floor(1000 / 60));
  ...

这样我们就不需要canvas。

结束语

第一次写这种东西,不喜勿喷。完成demo

你可能感兴趣的:(javascript,html5)