当前位置: 首页 > 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
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 08.Android之View事件问题
  • 2017-08-04 前端日报
  • es的写入过程
  • Gradle 5.0 正式版发布
  • HomeBrew常规使用教程
  • magento2项目上线注意事项
  • 百度地图API标注+时间轴组件
  • 半理解系列--Promise的进化史
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 浮动相关
  • 简析gRPC client 连接管理
  • 马上搞懂 GeoJSON
  • 算法之不定期更新(一)(2018-04-12)
  • 一个完整Java Web项目背后的密码
  • 再次简单明了总结flex布局,一看就懂...
  • Spring第一个helloWorld
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • #Spring-boot高级
  • #我与Java虚拟机的故事#连载08:书读百遍其义自见
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • (02)Hive SQL编译成MapReduce任务的过程
  • (12)Hive调优——count distinct去重优化
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (Redis使用系列) SpringBoot中Redis的RedisConfig 二
  • (补)B+树一些思想
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (二)springcloud实战之config配置中心
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (强烈推荐)移动端音视频从零到上手(下)
  • (收藏)Git和Repo扫盲——如何取得Android源代码
  • (四)鸿鹄云架构一服务注册中心
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转)Oracle存储过程编写经验和优化措施
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .NET/C# 使用反射注册事件
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • @Async注解的坑,小心
  • @data注解_一枚 架构师 也不会用的Lombok注解,相见恨晚