JS PC端调用摄像头录视频截图上传文件

news/2025/2/3 22:00:38/

创建 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>

http://www.ppmy.cn/news/469708.html

相关文章

二分类结局变量Logistic回归临床模型预测—— 模型评价(一)

本节讲的是二分类结局变量的临床模型预测,与之前讲的Cox回归不同,https://lijingxian19961016.blog.csdn.net/article/details/124088364https://lijingxian19961016.blog.csdn.net/article/details/124088364https://lijingxian19961016.blog.csdn.net/article/details/1240…

给清洁设备以“生命”,国邦从生产型制造走向服务型制造的转型之路|案例研究

国邦协同科技&#xff08;广州&#xff09;有限公司&#xff08;以下简称“国邦”&#xff09;成立于2011年&#xff0c;是行业领先的清洁解决方案服务商&#xff0c;致力于为客户提供全周期清洁解决方案&#xff0c;提高其清洁品质及效率。在2016年到2020年连续5年的时间里&am…

SSD颗粒介绍

SLC&#xff1a;每个Cell单元存储1bit信息&#xff0c;也就是只有0、1两种电压变化&#xff0c;结构简单&#xff0c;电压控制也快速&#xff0c;反映出来的特点就是寿命长&#xff0c;性能强&#xff0c;P/E寿命在1万到10万次之间&#xff0c;但缺点就是容量低而成本高&#x…

固态硬盘的分类有哪些

固态硬盘&#xff08;Solid State Disk或Solid State Drive&#xff0c;简称SSD&#xff09;&#xff0c;又称固态驱动器&#xff0c;是用固态电子存储芯片阵列制成的硬盘。 固态硬盘在接口的规范和定义、功能及使用方法上与普通硬盘的完全相同&#xff0c;在产品外形和尺寸上…

SSD存储颗粒的现在与未来

原文地址&#xff1a; http://www.mcplive.com.cn/index.php/article/index/id/11759/page/1 2011年泰国的洪水把机械硬盘的价格推高了不少&#xff0c;却给SSD固态硬盘带来了一个新的发展契机&#xff0c;光刻技术与半导体技术的快速发展&#xff0c;也让SSD的成本方面逐渐降…

Android LayoutInflater 监听单个控件渲染时长

在做布局优化的时候&#xff0c;需要在布局中定位到渲染时长比较长的控件去进行针对性的优化。那要怎么做呢&#xff1f;可以借助 LayoutInflater 的 Factory2 来实现 LayoutInflater.setFactory2() 方法用于设置 LayoutInflater.Factory2&#xff0c;它可以拦截和修改 Layout…

固态硬盘的SLC、MLC、TLC和QLC的区别

NOR Flash 和 NAND Flash是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR Flash 技术&#xff0c;彻底改变了原先由EPROM(Electrically Programmable Read-Only-Memory电可编程序只读存储器)和EEPROM(电可擦只读存储器Electrically Erasable Programmable R…

SSD固态硬盘颗粒SLC MLC TLC QLC有什么区别

NOR Flash 和 NAND Flash是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR Flash 技术&#xff0c;彻底改变了原先由EPROM(Electrically Programmable Read-Only-Memory电可编程序只读存储器)和EEPROM(电可擦只读存储器Electrically Erasable Programmable R…