• 4┃音视频直播系统之浏览器中通过 WebRTC 进行桌面共享


    一、共享桌面原理

    • 共享桌面在直播系统中是一个必备功能

    • 共享者:每秒钟抓取多次屏幕,每次抓取的屏幕都与上一次抓取的屏幕做比较,取它们的差值,然后对差值进行压缩;如果是第一次抓屏或切幕的情况,即本次抓取的屏幕与上一次抓取屏幕的变化率超过 80% 时,就做全屏的帧内压缩。最后再将压缩后的数据通过传输模块传送到观看端;数据到达观看端后,再进行解码,这样即可还原出整幅图片并显示出来

    • 远程控制端:当用户通过鼠标点击共享桌面的某个位置时,会首先计算出鼠标实际点击的位置,然后将其作为参数,通过信令发送给共享端。共享端收到信令后,会模拟本地鼠标,即调用相关的 API,完成最终的操作

    • 共享桌面的过程:抓屏、压缩编码、传输、解码、显示、控制

     

    二、抓取桌面

    • 浏览器 WebRTC 中提供了方法 var promise = navigator.mediaDevices.getDisplayMedia(constraints) 进行桌面的抓取

    • 共享桌面,大多数人知道的可能是RDP(Remote Desktop Protocal)协议,它是 Windows 系统下的共享桌面协议;还有一种更通用的远程桌面控制协议 VNC(Virtual Network Console),它可以实现在不同的操作系统上共享远程桌面,而 TeamViewer、Todesk 都是使用的该协议

    • 远程桌面协议一般分为桌面数据处理与信令控制两部分

    • 桌面数据:包括了桌面的抓取、编码、压缩、传输、解码和渲染

    • 信令控制:包括键盘事件、鼠标事件以及接收到这些事件消息后的相关处理等

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>share desktop by WebRTC</title>
    </head>
    
    <body>
        <button onclick="shareDesktop()">抓取桌面</button>
    </body>
    <script>
        // 抓取桌面
        function shareDesktop() {
            // 只有在 PC 下才能抓取桌面
            if (IsPC()) {
                // 开始捕获桌面数据
                navigator.mediaDevices.getDisplayMedia({ video: true })
                    .then(getDeskStream)
                    .catch(handleError);
                return true;
            }
            return false;
        }
    
        // 得到桌面数据流
        function getDeskStream(stream) {
            localStream = stream;
        }
    
        // 判断是否是PC
        function IsPC() {
            var userAgentInfo = navigator.userAgent;
            var Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'];
            var flag = true;
            for (var v = 0; v < Agents.length; v++) {
                if (userAgentInfo.indexOf(Agents[v]) > 0) {
                    flag = false;
                    break;
                }
            }
            return flag;
        }
    </script>
    
    </html>

     

     

    三、桌面展示

    • 桌面采集后,就可以通过 HTML 中的<video>标签将采集到的桌面展示出来

    • 当桌面数据被抓到之后,会触发 getDeskStream 函数

    • 在该函数中将获取到的 stream 与 video 标签联系起来,这样就可以显示桌面了

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>share desktop by WebRTC</title>
    </head>
    
    <body>
        <video autoplay playsinline id="deskVideo"></video>
        <button onclick="shareDesktop()">抓取桌面</button>
    </body>
    <script>
        var deskVideo = document.querySelect("video/deskVideo");
    
        // 抓取桌面
        function shareDesktop() {
            // 只有在 PC 下才能抓取桌面
            if (IsPC()) {
                // 开始捕获桌面数据
                navigator.mediaDevices.getDisplayMedia({ video: true })
                    .then(getDeskStream)
                    .catch(handleError);
                return true;
            }
            return false;
        }
    
        // 得到桌面数据流并播放
        function getDeskStream(stream) {
            localStream = stream;
            deskVideo.srcObject = stream;
        }
    
        // 判断是否是PC
        function IsPC() {
            var userAgentInfo = navigator.userAgent;
            var Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'];
            var flag = true;
            for (var v = 0; v < Agents.length; v++) {
                if (userAgentInfo.indexOf(Agents[v]) > 0) {
                    flag = false;
                    break;
                }
            }
            return flag;
        }
    </script>
    
    </html>

     

    四、录制桌面视频

    • 录制视频其实在上一章中详细说过,这里就不再重复了,这里只贴一下大概的逻辑代码

    • 首先通过 getDisplayMedia 方法获取到本地桌面数据

    • 然后将该流当作参数传给 MediaRecorder 对象

    • 并实现 ondataavailable 事件,最终将音视频流录制下来

    • 具体实现请参考上一篇文章自己进行完善

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>share desktop by WebRTC</title>
    </head>
    
    <body>
        <button onclick="startRecord()">开始录制</button>
    </body>
    <script>
        var buffer;
        
        function startRecord() {
            // 定义一个数组,用于缓存桌面数据,最终将数据存储到文件中
            buffer = [];
    
            var options = {
                mimeType: 'video/webm;codecs=vp8'
            }
    
            if (!MediaRecorder.isTypeSupported(options.mimeType)) {
                console.error(`${options.mimeType} is not supported!`);
                return;
            }
    
            try {
                // 创建录制对象,用于将桌面数据录制下来
                mediaRecorder = new MediaRecorder(localStream, options);
            } catch (e) {
                console.error('Failed to create MediaRecorder:', e);
                return;
            }
            // 当捕获到桌面数据后,该事件触发
            mediaRecorder.ondataavailable = handleDataAvailable;
            mediaRecorder.start(10);
        }
    
        function handleDataAvailable(e) {
            if (e && e.data && e.data.size > 0) {
                buffer.push(e.data);
            }
        }
    </script>
    
    </html>

     

  • 相关阅读:
    Spring的RestTemplate、RPC和HTTP
    亚马逊云科技大语言模型的创新科技
    python如何将c代码打包,上传
    【区块链 | 默克尔树】使用默克尔(Merkle)树实现NFT白名单
    Tomcat 的安装以及其中配置环境原理的详细说明
    Nginx配置转发
    动态规划一
    TB/T 3237 动车组用内装材料阻燃要求与测试
    喜相逢再递表港交所:非控股股东均亏损,已提前“套现”数千万元
    JS教程之 识别 JavaScript 数据类型:两种方法就足够了
  • 原文地址:https://www.cnblogs.com/autofelix/p/16265556.html