创建 Catcher 类
class Catcher {
URL; // 上传地址
dataStream; // 流数据
mediaStream; //媒体流
mediaRecorder; //录制对象
state; // 录制状态
constructor(options) {
this.video = document.getElementById(options.video);
this.URL = options.URL;
this.uploadParams = options.params;
}
/**
* 获取用户媒体设备并处理兼容的问题
* @param videoEnable {boolean} 是否启用摄像头
* @param audioEnable {boolean} 是否启用麦克风
* @param callback {Function} 处理回调
*/
getMedia(videoEnable, audioEnable, callback) {
navigator.getMedia =
navigator.getMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia ||
window.getMedia;
const constraints = {
video: videoEnable,
audio: audioEnable,
};
if (navigator.mediaDevices && navigator.mediaDevices.getMedia) {
navigator.mediaDevices
.getMedia(constraints)
.then(function (stream) {
callback(false, stream);
})
["catch"](function (err) {
callback(err);
});
} else if (navigator.getMedia) {
navigator.getMedia(
constraints,
function (stream) {
callback(false, stream);
},
function (err) {
callback(err);
}
);
} else {
callback(new Error("Not support userMedia"));
}
}
/**
* 关闭媒体流
* @param stream {MediaStream} 需要关闭的流
*/
closeStream(stream) {
if (typeof stream.stop === "function") {
stream.stop();
} else {
const trackList = [stream.getAudioTracks(), stream.getVideoTracks()];
for (let i = 0; i < trackList.length; i++) {
const tracks = trackList[i];
if (tracks && tracks.length > 0) {
for (let j = 0; j < tracks.length; j++) {
let track = tracks[j];
if (typeof track.stop === "function") {
track.stop();
}
}
}
}
}
}
init() {
if (this.video != null) {
this.state = false;
this.getMedia(true, true, (err, stream) => {
if (err) {
throw err;
} else {
this.mediaRecorder = new MediaRecorder(stream); // 创建 MediaRecorder 实例,记录获取到的媒体流
this.mediaStream = stream;
const chunks = [];
this.video.srcObject = stream;
this.video.play();
this.mediaRecorder.ondataavailable = function (e) {
this.blobs.push(e.data);
chunks.push(e.data);
};
this.mediaRecorder.blobs = [];
this.mediaRecorder.onstop = (e) => {
this.dataStream = new Blob(chunks, {
type: this.mediaRecorder.mimeType,
});
chunks = [];
this.uploadFile(this.dataStream);
};
}
});
}
}
//录制上传服务器
uploadFile(dataStream) {
const file = new File(
[dataStream],
"msr-" + new Date().toISOString().replace(/:|\./g, "-") + ".mp4",
{
type: "video/mp4",
}
);
const url = this.URL;
if ((url != undefined) & (url != null) & (url != "")) {
if (confirm("录制完成,是否上传录制文件?")) {
alert("正在上传录制文件!");
const formData = new FormData();
formData.append("file", file);
const params = this.uploadParams;
if (
(params != undefined) &
(params != null) &
(typeof params == "object")
) {
for (param in params) {
formData.append(param, params[params]);
}
}
fetch(url, {
method: "post",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: formData,
}).then((response) => {
if (response.status === 200) {
this.mediaRecorder = null;
this.mediaStream = null;
this.dataStream = null;
alert("上传成功");
} else {
alert("上传失败!");
}
});
}
}
}
// 截图并返回图片地址
screenshot() {
const canvas = document.createElement("canvas");
canvas.width = this.video.videoWidth;
canvas.height = this.video.videoHeight;
canvas
.getContext("2d")
.drawImage(this.video, 0, 0, canvas.width, canvas.height);
return canvas.toDataURL("image/png");
}
// 录制开始
startRecorder() {
if ((this.mediaRecorder != undefined) & (this.mediaRecorder != null)) {
this.state = true;
this.mediaRecorder.start();
}
}
// 录制结束
stopRecorder() {
if ((this.mediaRecorder != undefined) & (this.mediaRecorder != null)) {
this.state = false;
this.mediaRecorder.stop();
this.closeStream(this.mediaStream);
}
}
// 关闭摄像头
closeMedia() {
if ((this.mediaStream != undefined) & (this.mediaStream != null)) {
this.closeStream(this.mediaStream);
}
}
}
直接在HTML文件中调用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>View catch</title>
<style>
* {
padding: 0;
margin: 0;
}
.container {
display: flex;
}
#video {
background: skyblue;
}
.operation {
padding: 20px;
}
.operation button {
display: block;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div class="container">
<video
id="video"
width="500px"
height="300px"
autoplay="autoplay"
></video>
<div class="operation">
<button id="open">开启摄像头</button>
<button id="recorder">点击录制</button>
<button id="close">关闭摄像头</button>
<button id="screenshot">截图</button>
</div>
</div>
<script src="./js/catcher.js"></script>
<script>
const catcher = new Catcher({
video: "video",
uploadURI: "123",
params: {},
});
const open = document.getElementById("open");
const screenshot = document.getElementById("screenshot");
const recorder = document.getElementById("recorder");
const close = document.getElementById("close");
open.addEventListener("click", () => {
catcher.init();
});
screenshot.addEventListener("click", () => {
const src = catcher.screenshot();
const img = document.createElement("img");
img.src = src;
document.getElementsByTagName("body")[0].appendChild(img);
});
recorder.addEventListener("click", () => {
if (catcher.recorderState == false) {
recorder.innerText = "录制中";
catcher.startRecorder();
} else if (catcher.recorderState == true) {
recorder.innerText = "点击录制";
catcher.stopRecorder();
}
});
close.addEventListener("click", () => {
catcher.closeMedia();
});
</script>
</body>
</html>