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

武汉 大型 网站建设百度免费推广

武汉 大型 网站建设,百度免费推广,做网站可以用什么语言,男生女生做污事网站 localhost在浏览器中实现屏幕录制通常使用 MediaStream API 和 MediaRecorder API。下面是一个完整的示例,展示如何在Web页面中录制屏幕,并提供下载功能。 功能 选择屏幕或窗口进行录制开始/暂停/停止录制录制完成后可下载视频 核心技术 navigator.mediaDevice…

在浏览器中实现屏幕录制通常使用 MediaStream API 和 MediaRecorder API。下面是一个完整的示例,展示如何在Web页面中录制屏幕,并提供下载功能。

功能

  • 选择屏幕或窗口进行录制
  • 开始/暂停/停止录制
  • 录制完成后可下载视频

核心技术

  1. navigator.mediaDevices.getDisplayMedia():获取屏幕媒体流

  2. MediaRecorder:录制流并保存为视频文件

界面截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

案例源码:

<template><div class="rdp-recorder" :class="{ 'minimal-ui': minimalUI }"><!-- 悬浮的最小化控制面板 - 适合无感录制 --><div v-if="minimalUI" class="floating-controls"><div class="recording-status"><span class="record-indicator" :class="{ paused: isPaused }"></span><span class="timer">{{ formatTime(recordingTime) }}</span></div><div class="button-group"><buttonv-if="isPaused"class="icon-btn resume-btn"title="继续录制"@click="resumeRecording"></button><buttonv-else-if="isRecording"class="icon-btn pause-btn"title="暂停录制"@click="pauseRecording"></button><buttonv-if="isRecording"class="icon-btn stop-btn"title="停止录制"@click="stopRecording"></button></div><button class="icon-btn expand-btn" title="展开面板" @click="minimalUI = false"></button></div><!-- 完整控制面板 --><div v-else class="full-controls"><div class="panel-header"><h3>RDP会话录制</h3><button class="icon-btn minimize-btn" title="最小化" @click="minimalUI = true"></button></div><div class="controls"><buttonv-if="!isRecording":disabled="!hasSupport"class="btn start-btn"@click="startRDPRecording">开始录制RDP会话</button><template v-else><buttonv-if="!isPaused"class="btn pause-btn"@click="pauseRecording">暂停</button><buttonv-elseclass="btn resume-btn"@click="resumeRecording">继续</button><buttonclass="btn stop-btn"@click="stopRecording">停止录制</button></template></div><div v-if="isRecording" class="recording-info"><div class="recording-status"><span class="record-indicator" :class="{ paused: isPaused }"></span><span>{{ isPaused ? '已暂停' : '正在录制RDP会话...' }}</span></div><div class="timer">{{ formatTime(recordingTime) }}</div></div><div v-if="recordingURL" class="preview"><h3>录制预览</h3><video :src="recordingURL" controls width="100%"></video><button class="btn download-btn" @click="downloadRecording('rdp-recording.webm')">下载录制文件</button></div><div v-if="error" class="error">录制错误: {{ error }}</div><div v-if="!hasSupport" class="no-support">您的浏览器不支持屏幕录制功能</div><div class="settings"><h4>录制设置</h4><div class="checkbox-group"><label><input v-model="autoMinimize" type="checkbox" />开始录制后自动最小化</label></div><div class="checkbox-group"><label><input v-model="recordAudio" type="checkbox" />录制音频</label></div><button class="btn auto-start-btn" @click="autoStartRecording">自动选择RDP窗口录制</button><p class="tip">提示: 自动选择功能需要您在弹出框中选择RDP窗口</p></div></div></div>
</template><script lang="ts" setup>import { ref, onMounted, watch } from 'vue';import { useRDPScreenRecorder } from './useRDPScreenRecorder';// 组件名称定义defineOptions({name: 'RDPRecorderComponent',});// 状态const hasSupport = ref(false);const minimalUI = ref(false);const autoMinimize = ref(true);const recordAudio = ref(true);// 引入录屏功能const {isRecording,isPaused,recordingTime,recordingURL,error,startRecording,autoStartRDPRecording,pauseRecording,resumeRecording,stopRecording,downloadRecording,} = useRDPScreenRecorder();// 检查浏览器支持onMounted(() => {hasSupport.value = !!(navigator.mediaDevices &&navigator.mediaDevices.getDisplayMedia);});// 在录制开始后自动最小化UIwatch(isRecording, (newValue) => {if (newValue && autoMinimize.value) {minimalUI.value = true;}});// 格式化时间显示const formatTime = (seconds: number): string => {const mins = Math.floor(seconds / 60);const secs = seconds % 60;return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;};// 开始RDP会话录制const startRDPRecording = () => {startRecording({videoConstraints: {video: {frameRate: { ideal: 15 },cursor: 'always',displaySurface: 'window', // 窗口模式,便于选择RDP窗口logicalSurface: true,width: { ideal: 1280 },height: { ideal: 720 },},},includeAudio: recordAudio.value,captureApplicationAudio: recordAudio.value,mimeType: 'video/webm;codecs=vp9',});};// 自动开始RDP会话录制const autoStartRecording = () => {autoStartRDPRecording();};
</script><style scoped>.rdp-recorder {position: relative;max-width: 800px;margin: 0 auto;padding: 20px;font-family: Arial, sans-serif;border-radius: 8px;background-color: #fff;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);}.floating-controls {position: fixed;bottom: 20px;right: 20px;display: flex;align-items: center;padding: 8px 12px;background-color: rgba(33, 33, 33, 0.8);border-radius: 50px;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);z-index: 9999;color: white;}.recording-status {display: flex;align-items: center;gap: 8px;}.record-indicator {display: inline-block;width: 10px;height: 10px;border-radius: 50%;background-color: #F44336;animation: blink 1s infinite;}.record-indicator.paused {background-color: #FFC107;animation: none;}.button-group {display: flex;margin: 0 8px;}.icon-btn {background-color: transparent;border: none;color: white;width: 28px;height: 28px;border-radius: 50%;display: flex;align-items: center;justify-content: center;cursor: pointer;margin: 0 2px;font-size: 14px;}.icon-btn:hover {background-color: rgba(255, 255, 255, 0.2);}.minimize-btn, .expand-btn {font-size: 12px;}.panel-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 15px;}.panel-header h3 {margin: 0;}.controls {margin: 20px 0;display: flex;gap: 10px;}.btn {padding: 10px 15px;border: none;border-radius: 4px;cursor: pointer;font-weight: bold;transition: background-color 0.3s;}.start-btn {background-color: #4CAF50;color: white;}.pause-btn {background-color: #FFC107;color: #333;}.resume-btn {background-color: #2196F3;color: white;}.stop-btn {background-color: #F44336;color: white;}.download-btn {background-color: #673AB7;color: white;margin-top: 10px;}.auto-start-btn {background-color: #2196F3;color: white;}.btn:hover {opacity: 0.9;}.btn:disabled {background-color: #cccccc;cursor: not-allowed;}.recording-info {display: flex;align-items: center;justify-content: space-between;margin: 20px 0;padding: 10px;background-color: #f5f5f5;border-radius: 4px;}.timer {font-family: monospace;font-size: 1.2rem;}.floating-controls .timer {font-size: 1rem;}.preview {margin-top: 20px;}.error {color: #F44336;margin: 10px 0;padding: 10px;background-color: #FFEBEE;border-radius: 4px;}.no-support {color: #F44336;margin: 10px 0;padding: 10px;background-color: #FFEBEE;border-radius: 4px;}.settings {margin-top: 20px;padding: 15px;background-color: #f5f5f5;border-radius: 4px;}.settings h4 {margin-top: 0;margin-bottom: 15px;}.checkbox-group {margin-bottom: 10px;}.tip {font-size: 12px;color: #666;margin-top: 10px;}@keyframes blink {0% { opacity: 1; }50% { opacity: 0.4; }100% { opacity: 1; }}
</style>
// useRDPScreenRecorder.ts
import { ref, onUnmounted } from 'vue';export function useRDPScreenRecorder() {const isRecording = ref<boolean>(false);const isPaused = ref<boolean>(false);const recordingTime = ref<number>(0);const recordingURL = ref<string>('');const error = ref<string | null>(null);let mediaRecorder: MediaRecorder | null = null;let recordedChunks: Blob[] = [];let startTime = 0;let timerInterval: number | null = null;let combinedStream: MediaStream | null = null;interface RecordingOptions {videoConstraints?: MediaStreamConstraints;audioConstraints?: MediaStreamConstraints;mimeType?: string;timeslice?: number;includeAudio?: boolean;captureApplicationAudio?: boolean;}// 开始录制屏幕和音频const startRecording = async (options: RecordingOptions = {}) => {const defaultOptions: RecordingOptions = {videoConstraints: {video: {// 针对RDP窗口的优化设置frameRate: { ideal: 15 }, // 降低帧率以减少RDP连接的负担cursor: 'always', // 始终捕获光标displaySurface: 'window', // 优先尝试捕获窗口而非整个屏幕logicalSurface: true, // 捕获逻辑窗口表面而非物理显示width: { ideal: 1920 }, // 设置理想分辨率height: { ideal: 1080 },},},audioConstraints: {audio: {// 音频设置优化echoCancellation: true, // 回声消除noiseSuppression: true, // 噪声抑制autoGainControl: true, // 自动增益控制},},mimeType: 'video/webm;codecs=vp9', // VP9编码器在低带宽环境下表现更好timeslice: 1000, // 每秒获取一次数据includeAudio: true, // 是否包含麦克风音频captureApplicationAudio: true, // 是否尝试捕获应用程序音频};const config = { ...defaultOptions, ...options };recordedChunks = [];error.value = null;try {// 获取屏幕流,用户在选择对话框中应该选择RDP窗口const screenStream = await navigator.mediaDevices.getDisplayMedia(config.videoConstraints);// 处理录制结束screenStream.getVideoTracks()[0].onended = () => {stopRecording();};let streams = [screenStream];// 尝试捕获系统音频(RDP会话中的声音)// 注意:这依赖于浏览器和系统支持,可能不适用于所有环境if (config.captureApplicationAudio) {try {// 在某些浏览器中,系统音频可以通过getDisplayMedia的audio选项获取// 检查是否已经有音频轨道const hasAudioTrack = screenStream.getAudioTracks().length > 0;if (!hasAudioTrack) {console.warn('无法直接捕获RDP会话的系统音频,这在某些浏览器中是正常现象');}} catch (err) {console.warn('捕获系统音频失败:', err);}}// 如果需要麦克风音频,获取麦克风流if (config.includeAudio) {try {const audioStream = await navigator.mediaDevices.getUserMedia(config.audioConstraints);streams.push(audioStream);} catch (err) {console.warn('无法获取麦克风权限,继续仅录制视频', err);}}// 合并流combinedStream = new MediaStream();// 添加所有视频轨道streams.forEach(stream => {stream.getVideoTracks().forEach(track => {combinedStream.addTrack(track);});});// 添加所有音频轨道streams.forEach(stream => {stream.getAudioTracks().forEach(track => {combinedStream.addTrack(track);});});// 创建MediaRecorder,优化RDP场景的录制设置const recorderOptions: MediaRecorderOptions = {};if (config.mimeType) {// 检查MIME类型支持if (MediaRecorder.isTypeSupported(config.mimeType)) {recorderOptions.mimeType = config.mimeType;} else if (MediaRecorder.isTypeSupported('video/webm')) {recorderOptions.mimeType = 'video/webm'; // 降级}}// 可以添加录制质量设置// 对于RDP场景,可以考虑降低视频比特率以减少资源占用// 初始化录制器mediaRecorder = new MediaRecorder(combinedStream, recorderOptions);// 处理数据可用事件mediaRecorder.ondataavailable = (event) => {if (event.data.size > 0) {recordedChunks.push(event.data);}};// 处理录制结束事件mediaRecorder.onstop = () => {const mimeType = mediaRecorder?.mimeType || 'video/webm';const blob = new Blob(recordedChunks, { type: mimeType });recordingURL.value = URL.createObjectURL(blob);isRecording.value = false;if (timerInterval) {clearInterval(timerInterval);timerInterval = null;}};// 开始录制mediaRecorder.start(config.timeslice);isRecording.value = true;isPaused.value = false;startTime = Date.now();// 启动计时器timerInterval = window.setInterval(() => {recordingTime.value = Math.floor((Date.now() - startTime) / 1000);}, 1000);} catch (err: any) {error.value = err.message || '录制失败';console.error('录制失败:', err);}};// 自动开始录制RDP窗口(无感知方式)const autoStartRDPRecording = async () => {try {// 尝试自动开始录制,但需要用户交互触发// 建议在用户点击页面其他地方或进行其他交互后调用await startRecording({videoConstraints: {video: {// 针对RDP会话的优化设置frameRate: { ideal: 10 }, // 降低帧率可减轻网络负担cursor: 'always',displaySurface: 'window', // 设置为窗口模式,方便用户选择RDP窗口logicalSurface: true,// 减少分辨率可以降低CPU使用率width: { ideal: 1280 },height: { ideal: 720 },},},// 降低录制频率,减少资源占用timeslice: 2000,captureApplicationAudio: true,});console.log('RDP录制已自动开始,请在弹出的对话框中选择RDP窗口');} catch (err) {console.error('自动开始RDP录制失败:', err);}};// 暂停录制const pauseRecording = () => {if (mediaRecorder && isRecording.value && !isPaused.value && mediaRecorder.state === 'recording') {mediaRecorder.pause();isPaused.value = true;if (timerInterval) {clearInterval(timerInterval);timerInterval = null;}}};// 继续录制const resumeRecording = () => {if (mediaRecorder && isRecording.value && isPaused.value && mediaRecorder.state === 'paused') {mediaRecorder.resume();isPaused.value = false;// 重启计时器timerInterval = window.setInterval(() => {recordingTime.value = Math.floor((Date.now() - startTime) / 1000);}, 1000);}};// 停止录制const stopRecording = () => {if (mediaRecorder && isRecording.value &&(mediaRecorder.state === 'recording' || mediaRecorder.state === 'paused')) {mediaRecorder.stop();// 停止所有轨道if (combinedStream) {combinedStream.getTracks().forEach(track => track.stop());}if (timerInterval) {clearInterval(timerInterval);timerInterval = null;}}};// 下载录制内容const downloadRecording = (filename = 'rdp-recording.webm') => {if (recordingURL.value) {const a = document.createElement('a');document.body.appendChild(a);a.style.display = 'none';a.href = recordingURL.value;a.download = filename;a.click();document.body.removeChild(a);}};// 清理函数onUnmounted(() => {stopRecording();if (recordingURL.value) {URL.revokeObjectURL(recordingURL.value);}});return {isRecording,isPaused,recordingTime,recordingURL,error,startRecording,autoStartRDPRecording,pauseRecording,resumeRecording,stopRecording,downloadRecording,};
}
http://www.dtcms.com/wzjs/86509.html

相关文章:

  • 什么主题和风格的网站好平台搭建
  • 微网站可以做商城吗百度网盘下载速度
  • 西安网站建设qq群号b站推广网站
  • wordpress安装后查看站点失败优化师培训机构
  • 求个没封的a站yw1129cm桂林seo排名
  • 浙江省建设网站徐叨法网络营销的盈利模式
  • w网站开发文献十大广告公司
  • 网站制作 用户登录系统营销渠道管理
  • 济南做网站的好公司有哪些最新足球赛事
  • 杭州交易网站建设百度网盟推广官方网站
  • 做愛偷拍视频网站合肥优化营商环境
  • 怎么做自己的博客网站最近发生的重大新闻事件
  • 中国建设银行网站首页公司机构免费下载官方百度
  • 巴州建设局网站谷歌推广公司哪家好
  • 网站开发网站模板设计口碑营销怎么做
  • 网站建设与管理实用教程课后答案免费b站软件推广网站
  • 宝安网站建设制作seo管理软件
  • 成都锦江规划建设局网站南京seo排名扣费
  • 怎么建立一个网站链接中国去中心化搜索引擎
  • 中国建设银行青浦支行网站南京网站seo
  • 小型企业网站模板下载网站优化seo教程
  • 汕尾好网站建设推广爱站小工具
  • 给个手机网站就这么难吗推广引流哪个软件最好
  • 网站更换主机需要怎么做百度题库
  • php中网站搜索功能实现5118网站如何使用免费版
  • 国外优秀电商网站网站优化的方法
  • 十进十建 网站建设工作总结网络推广有哪些
  • 做网站的有哪些宁波网站推广大全
  • 团购网站怎么做市场营销策划方案
  • 微信里我的微站是怎么弄的新媒体运营培训