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

(webRTC、RecordRTC):navigator.mediaDevices undefined

RecordRTC的视频录制及播放
recordRTC是前端的一个视频录制的工具,用于音频+视频+屏幕+画布(2D+3D动画)录制的WebRTC JavaScript库。

最近做了一个通过webRTC实现在线视频功能的网页,在自己的电脑上用localhost打开两个网页是没问题的,但是设置了一个简单的HTTP请求的NodeJS服务器之后,在局域网中用ip地址访问就不行了,浏览器会弹出 navigator.mediaDevices undefined 的错误。

通过 MediaDevices.getUserMedia() 获取用户多媒体权限时,需要注意其只工作于以下三种环境:
localhost 域
开启了 HTTPS 的域
使用 file:/// 协议打开的本地文件
如果当前文档未安全加载,navigator.mediaDevices 将为 undefined,并且不能使用getUserMedia()。

所以对应的解决方案也出来了:

  1. 创建HTTPS服务器,用HTTPS协议的方式发送请求。

  2. 在HTTP服务器上,可设置Chrome 的相应参数:

在chrome浏览器的地址栏中输入: chrome://flags/#unsafely-treat-insecure-origin-as-secure,将该 flag 切换成 enable 状态;
在输入框中填写需要开启的域名或地址,如果有多个,则以逗号分隔;
重启浏览器后生效。
第二种方式只适合自己测试用,亲测可行~ 撒花~

<!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>Document</title>
  </head>
  <body>
    <script>
      navigator.mediaDevices
        .getUserMedia({
          audio: true,
          video: {
            width: { min: 1024, ideal: 1280, max: 1920 },
            height: { min: 776, ideal: 720, max: 1080 },
          },
        })
        .then(function (stream) {
          console.log("stream", stream);

          /* 使用这个stream stream */
        })
        .catch(function (err) {
          console.log("err", err);

          /* 处理error */
        });
    </script>
  </body>
</html>

<!DOCTYPE html>
<img 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>Document</title>
    <script src="https://www.WebRTC-Experiment.com/RecordRTC.js"></script>
    <!-- <script script src=" https://unpkg.com/@vueuse/shared "> </script>
    <script src="https://unpkg.com/@vueuse/core"></script> -->
</head>
<video id="myVideo" playsinline controls preload="auto" playsinline autoplay poster controlslist="nodownload"
    controlslist="nofullscreen" width="500" height="500">
</video>
<canvas id="canvas"></canvas>
<img id="img"></img>
<video id="myVideo1" playsinline controls preload="auto" playsinline autoplay poster controlslist="nodownload"
    controlslist="nofullscreen" width="500" height="500">
</video>
<button onclick="openRecord()">开启录制</button>
<button onclick="play()">视频播放</button>
<button onclick="videoDown()">视频下载</button>
<button onclick="screenshot()">截图</button>

<body>
    <script>
        /*
            string数据库名称,number版本号不传默认为1
        */

        // console.log(useUserMedia)
        var myVideo = document.getElementById('myVideo')
        var canvas = document.getElementById('canvas')
        var img = document.getElementById('img')
        let recorder = new Object();
        var videoStearm = new Object();
        function openRecord() {
            navigator.mediaDevices.getUserMedia({
                video: {
                    width: 1280,
                    height: 720,
                    frameRate: 24
                },
                audio: true,
                elementClass: 'multi-streams-mixer'
            }).then(async function (stearm) {
                videoStearm = stearm
                //把流赋值给video 实现实时录制
                myVideo.srcObject = stearm;
                console.log(myVideo.srcObject, 'srcobject')
                //立马开始播放视频流
                myVideo.play();
                recorder = RecordRTC(stearm, {
                    type: 'video',
                    //视频类型
                    mimeType: 'video/mp4',
                    timeSlice: 1000,
                    //该回调函数必须和上面的timeSlice分片时间配合使用
                    ondataavailable: function (blob) {
                        // blob为每一秒的视频片段
                        console.log(blob, '00000000')
                    },
                    // 获取时间片段的时间戳
                    onTimeStamp: function (timestamp) {
                        console.log(timestamp)
                    },
                    bitsPerSecond: 128000,
                })
                console.log(stearm, '视频流');
                //开启录制
                recorder.startRecording()


                const sleep = m => new Promise(r => setTimeout(r, m));
                await sleep(10000);
                //十秒后结束视频录制
                recorder.stopRecording(function (audioURL) {
                    // window.open(audioURL)
                    close()
                })

            }).catch((err) => { console.log('用户未开启视频权限') })
        }
        //视频下载
        function videoDown() {
            let blob = recorder.getBlob();
            console.log(blob, '0000000')
            //视频下载 invokeSaveAsDialog(参数1为视频流blob,参数2为视频类型)
            invokeSaveAsDialog(blob, 'video.mp4');
        }
        //视频播放
        function play() {
            let url = recorder.toURL();
            myVideo1.src = url
        }
        //关闭浏览器视频音频
        function close() {
            console.log(1234)
            console.log(videoStearm, '0000')
            console.log(videoStearm.getTracks(), '0000');
            videoStearm.getTracks()[0].stop()
            videoStearm.getTracks()[1].stop()
        }
        //截图
        function screenshot() {
                //截屏录制页面的第一个截图
                canvas.width = myVideo.width
                canvas.height = myVideo.height
                canvas.getContext('2d').drawImage(myVideo, 0, 0, canvas.width, canvas.height)
                let url = canvas.toDataURL('image/jpeg')
                console.log(url, '0909')
        }
    </script>
</body>

</html>

相关文章:

  • 旋转矩阵转欧拉角,转四元数
  • nginx实现双向认证
  • 基于GStreamer和FFmpeg的OpenCV安装和使用
  • 高项 11 风险管理
  • 字节12年测试经验,从零基础软件测试到功能测试到自动化测试到测试开发,我整理了这二份8000字入门到入职的学习指南
  • SQL 为什么历经半个世纪却经久不衰?
  • 【数据结构初阶】八大排序(三)——归并排序计数排序
  • VI 使用技巧
  • Disruptor生产和消费模式详解及高级应用(并行模式)
  • [算法周训 3] 字符串训练2
  • 判断月份所在的季节
  • 大数据毕设选题 - flask疫情数据可视化系统(python)
  • 记录第一次开源流计算框架Flink代码的贡献
  • 共码未来 | 助力实现事半功倍的前端开发体验
  • 客户端存储localStorage和sessionStorage以及Cookie
  • hadoop集群管理系统搭建规划说明
  • nodejs调试方法
  • React组件设计模式(一)
  • spring-boot List转Page
  • SpringBoot 实战 (三) | 配置文件详解
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 类orAPI - 收藏集 - 掘金
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 排序(1):冒泡排序
  • 微信开放平台全网发布【失败】的几点排查方法
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 一天一个设计模式之JS实现——适配器模式
  • ​520就是要宠粉,你的心头书我买单
  • ​如何在iOS手机上查看应用日志
  • !$boo在php中什么意思,php前戏
  • #define用法
  • #QT(一种朴素的计算器实现方法)
  • #微信小程序(布局、渲染层基础知识)
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (HAL库版)freeRTOS移植STMF103
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (学习日记)2024.02.29:UCOSIII第二节
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .NET Core跨平台微服务学习资源
  • .Net Memory Profiler的使用举例
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • .net经典笔试题
  • .NET开发者必备的11款免费工具
  • @entity 不限字节长度的类型_一文读懂Redis常见对象类型的底层数据结构
  • [ NOI 2001 ] 食物链
  • [Android Studio] 开发Java 程序
  • [AR Foundation] 人脸检测的流程
  • [BZOJ 3531][Sdoi2014]旅行(树链剖分+线段树)
  • [C/C++]关于C++11中的std::move和std::forward
  • [C/C++]数据结构 栈和队列()
  • [COGS 622] [NOIP2011] 玛雅游戏 模拟