首页 > 其他分享 >摄像机流添加OSD

摄像机流添加OSD

时间:2023-11-07 09:16:01浏览次数:30  
标签:canvas const ctx 摄像机 videoFrame 添加 new videoTrack OSD

export default class MediaStreamMixer {
	constructor() {
	}

	/**
	 *
	 * @param opts
	 */
	mix(opts) {
		let {audioTrack, videoTrack, stream} = opts || {};
		const ms = new MediaStream();
		if (stream instanceof MediaStream) {
			audioTrack = stream.getAudioTracks()[0];
			videoTrack = stream.getVideoTracks()[0];
		}
		if (audioTrack instanceof MediaStreamTrack && audioTrack.kind === 'audio') {
			ms.addTrack(audioTrack);
		}
		//if (videoTrack instanceof MediaStreamTrack && videoTrack.kind === 'video') {
		const mixed = this.mixVideo(videoTrack);
		ms.addTrack(mixed);
		//}
		return ms;
	}

	mixVideo(videoTrack) {
		const canvas = document.createElement('canvas');
		const context = canvas.getContext('2d');
		if (videoTrack) {
			const trackProcessor = new MediaStreamTrackProcessor(videoTrack);
			const frameReader = trackProcessor.readable.getReader();
			const frameParser = ({done, value: videoFrame}) => {
				if (done) return
				this.#draw(context, videoFrame.displayWidth, videoFrame.displayHeight, videoFrame);
				videoFrame.close();
				frameReader.read().then(data => frameParser(data));
			}
			frameReader.read().then(data => frameParser(data));
		} else {
			const draw = () => this.#draw(context, 1280, 720, null, '虚拟视频');
			draw();
			setInterval(draw.bind(this), 1E3);
		}
		return canvas.captureStream().getVideoTracks()[0];
	}


	mixVideo2(videoTrack) {
		if (videoTrack) {
			const canvas = new OffscreenCanvas(1, 1);//document.createElement('canvas');
			const context = canvas.getContext('2d');
			const trackProcessor = new MediaStreamTrackProcessor({track: videoTrack});
			const trackGenerator = new MediaStreamTrackGenerator({kind: "video"});
			const transformer = new TransformStream({
				transform: async (videoFrame, controller) => {
					this.#draw(context, videoFrame.displayWidth, videoFrame.displayHeight, videoFrame);
					const newFrame = new VideoFrame(canvas, {timestamp: +new Date()});
					videoFrame.close();
					controller.enqueue(newFrame);
				}
			});
			trackProcessor.readable.pipeThrough(transformer).pipeTo(trackGenerator.writable);
			return trackGenerator;
		} else {
			const canvas = document.createElement('canvas');
			const context = canvas.getContext('2d');
			setInterval(() => this.#draw(context, 640, 480, null), 1E3);
			return canvas.captureStream().getVideoTracks()[0];
		}
	}

	#draw(ctx, width, height, img, osd = '') {
		ctx.canvas.width = width;
		ctx.canvas.height = height;
		if (img) {
			ctx.drawImage(img, 0, 0);
		} else {
			ctx.fillStyle = '#000';
			ctx.fillRect(0, 0, width, height);
		}
		const fontSize = Math.max(12, height / 20 | 1);
		const [textHeight, margin, padding] = [fontSize, fontSize * 0.4, fontSize * 0.2];
		ctx.font = `${fontSize}px msyh`;
		let text = new Date().toLocaleString();
		let textWidth = ctx.measureText(text).width;
		this.#drawText(ctx, text, margin, margin, textWidth, textHeight, padding);

		if (osd) {
			text = osd;
			textWidth = ctx.measureText(text).width;
			this.#drawText(ctx, text, width - (textWidth + 2 * padding + margin), height - (textHeight + 2 * padding + margin), textWidth, textHeight, padding);
		}
	}

	#drawText(ctx, text, x, y, textWidth, textHeight, padding = 0) {
		const [w, h] = [textWidth + 2 * padding, textHeight + 2 * padding];
		ctx.fillStyle = '#808080c0';
		ctx.fillRect(x, y, w, h);
		ctx.fillStyle = '#fff';
		ctx.textAlign = 'center';
		ctx.textBaseline = 'middle';
		ctx.fillText(text, x + w / 2, y + h / 1.75);
	}
}

标签:canvas,const,ctx,摄像机,videoFrame,添加,new,videoTrack,OSD
From: https://www.cnblogs.com/zh33gl/p/17814245.html

相关文章

  • 如何在Vue.js中添加headers(标头) 使用 axios,单独请求,所有请求 添加请求头
    如何在Vue.js中添加headers(标头)使用axios,单独请求,所有请求添加请求头Vue.js是一个流行的前端框架,它以其简单易用的API和高度可组合的架构而闻名。当你构建一个Web应用时,你通常会使用一个HTTP客户端来与API交互。该客户端可以是一个浏览器内部的XMLHttpRequest,也可以......
  • 后端添加校验规则
    添加校验规则防止数据库中的数据混乱;1..NETCore中内置了对数据校验的支持,在System.ComponentModel.DataAnnotations这个命名空间下,比如【Required】【EmailAddress】【RegularExpresion】长度限制minlength等;-2.内置的校验机制问题,校验规则人都是和模型类耦合在......
  • 操作步骤:安防视频LiteCVR如何使用ONVIF探测添加设备通道?
    随着视频监控与数字化时代的来临,视频监控在各领域得到了广泛的应用。第四代视频监控是基于云计算的视频监控,云计算监控实现了视频监控接入互联网的飞跃,将安防视频监控的价值充分发挥,应用更灵活。有用户想通过onvif探测进行添加设备通道,却不知如何操作,今天我们来分享一下具体操作步......
  • Objectarx Wizards 2010中添加成员变量功能移植到Objectarx Wizards 2018中
     ——工欲善其事必先利其器 虽然AutoCADObjectarx代码没写几行,但对于ObjectarxWizards的折腾却不能少。这几天学习Com封装,找到一篇文章(教程),学习过程中发现原来ObjectarxWizards中添加成员变量的功能不错,可惜在高版本中给阉割了,于是想着能不能把此功能从低版本移植到高版......
  • prometheus添加自定义监控与告警(etcd为例)
    一、步骤及注意事项(前提,部署参考部署篇)一般etcd集群会开启HTTPS认证,因此访问etcd需要对应的证书使用证书创建etcd的secret将etcd的secret挂在到prometheus创建etcd的servicemonitor对象(匹配kube-system空间下具有k8s-app=etcd标签的service)创建service关联被监控对象二、......
  • 麒麟KYLINIOS软件仓库搭建03-软件仓库添加新版本的软件包
    原文链接:麒麟KYLINIOS软件仓库搭建03-软件仓库添加新版本的软件包hello,大家好啊,今天给大家带来麒麟桌面操作系统软件仓库搭建的文章03-软件仓库添加新版本的软件包,本篇文章主要给大家介绍了如何在麒麟桌面操作系统2203-x86版本上,为搭建好内网软件仓库源中添加新版本的软件包,本系列......
  • 103 添加日志
    1,nuget安装log4net2,assemblyinfo追加:[assembly:log4net.Config.XmlConfigurator(ConfigFile="log4net.Config",ConfigFileExtension="config",Watch=true)]3,增加:<sectionname="log4net"type="log4net.Config.Log4NetConf......
  • 百度资源平台 “该站点为低质站点,暂不可添加”解决方法
      当百度搜索资源平台显示“该站点为低质站点,暂不可添加,请持续优化后,再行尝试”时,这可能让网站管理员感到困惑和沮丧。但不必担心,我们可以采取一些步骤来解决这个问题,提高网站的质量,以便将其添加到百度搜索资源平台。了解问题的原因首先,让我们来了解一下为什么您的网站被标......
  • 废弃主机安装ubuntu开samba文件夹共享给小米摄像机监控NAS存储
    安装sshsudoapt-getinstallopenssh-serversudosystemctlenable--nowsshsudoapt-getinstallnet-toolsubuntu安装sambasudoaptupdatesudoaptupgradesudoapt-getinstallsambamkdir/sharesudochmod777/share-Rsudocp/etc/samba/smb.conf/etc/samba......
  • 麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包
    原文链接:麒麟KYLINIOS软件仓库搭建02-软件仓库添加新的软件包hello,大家好啊,今天给大家带来麒麟桌面操作系统软件仓库搭建的文章02-软件仓库添加新的软件包,本篇文章主要给大家介绍了如何在麒麟桌面操作系统2203-x86版本上,为搭建好内网软件仓库源中添加新的类型软件包,本系列共有三个......