当前位置: 首页 > news >正文

音视频开发远端未发布视频占位图

音视频开发时候,如果对方未发布视频,或者后面才发布视频,或停止发送流时,占位图的优势就有了;
总结一句话就是:比黑屏好;

效果图

请添加图片描述

调用API
/* 先new一个@params: parentEle: HTMLElement; 说明:父元素;@params: useName: String;   说明:用户姓名;
*/
const  avatarSpace = new AvatarCanvasSpace(parentEle, useName);
// 单独更新名字
avatarSpace.updateUserName(useName);
// 占位方式1:绘制Canvas占位
avatarSpace.createCavas();
// 占位方式2:绘制Video占位
avatarSpace.createVideo();// 清理掉之前父元素插入的占位
avatarSpace.clearRepeatCreate();
// 销毁
avatarSpace.destroy();
核心方法
// 头像占位
class AvatarCameraSpace {video: HTMLVideoElement | any;myCanvas: HTMLCanvasElement | any;ctx: CanvasRenderingContext2D | any ;streamCanvas: MediaStream | any;parentDiv: HTMLElement | any;useName: string | any;constructor(parentDiv: HTMLElement, useName: string) {this.initCanvasAndVideo();this.parentDiv = parentDiv;this.useName = useName;}initCanvasAndVideo() {this.video = document.createElement('video');this.myCanvas = document.createElement('canvas');this.ctx = this.myCanvas.getContext('2d');// 考虑占位1秒捕获1帧也足够用了this.streamCanvas = this.myCanvas.captureStream(1);this.addVideoAttributes();}// 添加属性的方法addVideoAttributes() {// 需要添加的属性列表(键值对形式)const attributes = {// 自动播放autoplay: '',// 控制视频在inline(内嵌)模式下播放,而非默认的全屏播放(尤其针对 iOS 设备)playsinline: '','webkit-playsinline': 'true',// 这是腾讯 X5 内核(微信、QQ、部分手机浏览器采用的内核)的私有属性,强制视频使用 H5 播放器,而非 X5 内核默认的全屏播放器。'x5-video-player-type': 'h5',// 腾讯 X5 内核的私有属性,进一步强化内嵌播放行为,确保视频在 X5 内核中不会自动全屏,与标准 playsinline 功能一致,但仅针对 X5 环境生效'x5-playsinline': 'true',};// 循环添加属性Object.entries(attributes).forEach(([key, value]) => {this.video.setAttribute(key, value);});// 补充:现代浏览器自动播放通常需要静音(可选,根据需求添加)this.video.muted = true; // 直接赋值(muted 是布尔属性,true 表示启用)}updateUserName(useName: string) {this.useName = useName;}// 创建canvas占位createCavas() {// 防止重复创建this.clearRepeatCreate();const canvas = this.myCanvas;const ctx = this.ctx;if (!canvas || !ctx) {return;};this.parentDiv.innerHTML = '';this.parentDiv.appendChild(canvas);this.drawCanvas();}// 绘制用户头像占位drawCanvas() {const canvas = this.myCanvas;const ctx = this.ctx;if (!canvas || !ctx) {return;};const useName = this.useName;canvas.width = 1280;canvas.height = 720;// 设置样式让canvas自适应父容器canvas.style.width = '100%';canvas.style.height = '100%';canvas.style.display = 'block';// 绘制黑色背景this.ctx.fillStyle = '#000000';ctx.fillRect(0, 0, canvas.width, canvas.height);// 计算蓝色方框的位置(居中)const boxSize = 120;const boxX = (canvas.width - boxSize) / 2;const boxY = (canvas.height - boxSize) / 2 - 50; // 稍微向上移动一点,给下方名字留出空间// 圆角半径(可根据需要调整,建议10-20之间)const borderRadius = 15;// 绘制蓝色方框ctx.fillStyle = '#1689F4';// 开始绘制路径ctx.beginPath();// 左上角圆角ctx.moveTo(boxX + borderRadius, boxY);// 上边缘ctx.lineTo(boxX + boxSize - borderRadius, boxY);// 右上角圆角ctx.arcTo(boxX + boxSize, boxY, boxX + boxSize, boxY + borderRadius, borderRadius);// 右边缘ctx.lineTo(boxX + boxSize, boxY + boxSize - borderRadius);// 右下角圆角ctx.arcTo(boxX + boxSize, boxY + boxSize, boxX + boxSize - borderRadius, boxY + boxSize, borderRadius);// 下边缘ctx.lineTo(boxX + borderRadius, boxY + boxSize);// 左下角圆角ctx.arcTo(boxX, boxY + boxSize, boxX, boxY + boxSize - borderRadius, borderRadius);// 左边缘ctx.lineTo(boxX, boxY + borderRadius);// 左上角收尾圆角ctx.arcTo(boxX, boxY, boxX + borderRadius, boxY, borderRadius);// 闭合路径ctx.closePath();// 填充路径(绘制出圆角矩形)ctx.fill();// 获取名字的第一个字const firstChar = useName.charAt(0);// 在蓝色方框中绘制第一个字(居中)ctx.fillStyle = '#FFFFFF'; // 白色文字ctx.font = '80px Arial';ctx.textAlign = 'center';ctx.textBaseline = 'middle';ctx.fillText(firstChar, boxX + boxSize / 2, boxY + boxSize / 2);// 在蓝色方框下方绘制全名ctx.font = '40px Arial';ctx.fillText(`${useName.length > 12 ? (useName.substring(0, 12) + '...') : useName}`, canvas.width / 2, boxY + boxSize + 60);console.log('drawCanvas', useName);}// 创建video占位createVideo() {// 防止重复创建this.clearRepeatCreate();const canvas = this.myCanvas;const ctx = this.ctx;const video = this.video;if (!canvas || !ctx) {return;};this.parentDiv.innerHTML = '';this.parentDiv.appendChild(video);// 设置样式让video自适应父容器video.style.width = '100%';video.style.height = '100%';video.style.display = 'block';/*直接给流就行; canvas重绘后captureStream会自己捕捉更新video 元素会显示 canvas 的当前状态; 如果 canvas 的内容不再更新,video 元素就会停留在最后一帧;如果是WebRTC则会持续读取流,实时显示视频; 我们的需求是占位所以足够了*/video.srcObject = this.streamCanvas;video.play();/* 绘制用户头像占位因为video会显示canvas的当前状态,所以我们需要在canvas上绘制用户头像占位; 否则video会显示一个黑色的方框;*/this.drawCanvas();}// 父元素是否还存在parentDivIsExists()  {// this.parentDiv.isConnected();  这个方法在ie11下不支持return document.body.contains(this.parentDiv);}myCanvasIsExists() {if (!this.myCanvas) { return false; }return document.body.contains(this.myCanvas);}myVideoIsExists() {if (!this.video) { return false; }return document.body.contains(this.video);}clearRepeatCreate() {try {// 如果当前canvas还存在,则移除if (this.parentDiv.contains(this.myCanvas)) {this.parentDiv.removeChild(this.myCanvas);}// 如果当前video还存在,则移除if (this.parentDiv.contains(this.video)) {this.parentDiv.removeChild(this.video);}} catch(err) {console.log('销毁重复创建失败', err);}}// 销毁destroy() {if (!this.video) { return; }this.clearRepeatCreate();this.video = null;this.myCanvas = null;this.ctx = null;this.streamCanvas = null;this.useName = null;}
}
export default AvatarCameraSpace;
http://www.dtcms.com/a/512679.html

相关文章:

  • 贵阳网站开发推荐你的网站赚钱吗
  • 上海备案证查询网站查询网站查询系统桂林论坛网站建设
  • QT6中三种设置控件及窗口大小的函数
  • 现在的网站前端用什么做综合返利商城网站建设
  • 河南省建设厅网网站首页没备案的网站收录
  • 织梦网站标题被改学校招生网络营销方案
  • 从0到1:如何用统计学“看透”不同睡眠PSG数据集的差异(域偏差分析实战)
  • 如何做淘宝优惠卷网站网站业务员怎么给客户做方案
  • 网站空间后台登录长沙seo服务
  • 灵敏度、稳定性、便携性三重突破——小吉BL-08plus为何成禽病防控新标配?
  • ubuntu 中使用 lftp 命令行工具传输文件
  • 推荐5款中文打字速度测试软件:无需下载即可使用
  • 网站建设基础服务wordpress polling
  • 长春 网站 设计公司wordpress 权限
  • 什么在线做动图的网站比较好织梦调用wordpress
  • 用 Python 给 Amazon 做“全身 CT”——可量产、可扩展的商品详情爬虫实战
  • 开箱即用,15分钟极速部署:富唯智能精密仪器搬运机器人重塑工业自动化
  • 网站建设个人实训报告seo免费入门教程
  • 一个服务器下怎么做两个网站吗网站上海备案查询系统
  • STM32实现呼吸灯效果原理
  • 做营销网站要多少钱网站开发平台建设
  • html css js网页制作成品——HTML+CSS仙台有树电视剧网页设计(5页)附源码
  • 开发避坑指南(64):修复IllegalArgumentException:参数值类型与期望类型不匹配
  • 企业网站怎样做seo优化 应该如何做凡科建站官网怎么样
  • 【Java进阶】GC友好的编程方式
  • 甘肃肃第八建设集团网站福州市高速公路建设指挥部网站
  • 鸿蒙NEXT媒体开发全栈解析:从播放器到录屏的一站式解决方案
  • 郑州做网站排名dede网站首页
  • python 做网站很快吗广州自助网站推广建站
  • AD22 热风焊盘在哪设置