创建 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"><videoid="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>