6.webrtc音视频数据采集

通过getUserMedia这个方法采集音视频数据,在这个方法里面有一个重要的参数 constraints,这个constraints就是类型,这个类型比较特别,在这个类型里面有两个元素,一个是video,一个是audio,也就是说分别对video和audio做一些限制,既可以是布尔类型,也可以是这种复杂的类型,如果它是布尔型,也就是这里我们设置video和audio都是true的话,那么它采集的数据既有音频数据也有视频数据,如果我们只要其中一项,比如只要音频,那就是audio等于true,video等于false。如果把它当成这种复制类型的话,就可以设置一些具体的控制了,比如说视频,可以控制分辨率,比如设置成640*480,720p,1080p等等,这些都可以设置,还可以设置帧率,15帧,25帧,30帧,同样对于音频来说,也可以设置音频相关的,比如音频的延迟,音量的大小,单声道还是双声道等等都可以进行控制,这方面的具体讲解我们会在下面的课程中做详细介绍。

实战:

index.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>WebRTC caoture video and audio</title>

</head>

<body>

       <!--video元素里可以显示我们捕获的音视频数据-->

       <!--autoplay属性表示我们拿到视频源的时候直接将它播放出来,playsinline 表示在浏览器的页面中播放-->

       <video  autoplay playsinline  id="player"></video>

       <!--加入一段javascript源码,通过调用  getusermedia这个api来捕获音视频数据,-->

       <script  src = './js/client.js'  ></script>

</body>

</html>

client.js

'use strict'





//首先获取到在html中定义的vedio标签

var videoplay = document.querySelector('video#player');

//实现获取流之后的方法,将获取到的流赋值给我们在html中定义的vedio标签

function gotMediaStream(stream) {

    //指定标签获取视频流的数据源

    videoplay.srcObject = stream;

}





//获取失败 打印出错信息

function handleError(err) {

    console.log('getUserMedia error:', err);

}



//如果这个方法不存在,则打印

if(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia){

    console.log('getUserMedia is not supported!');

}else {

    //设置参数,同时采集音频和视频数组

    var constraints = {

            video:true,

            audio:true

    }





    //如果存在,就调用这个方法,成功进入成功方法,失败进入失败方法

    navigator.mediaDevices.getUserMedia(constraints)

        .then(gotMediaStream)

        .catch(handleError);

}

执行 

node server.js

效果

 

 

6-2 WebRTC_API_适配(浏览器适配方法)

 

 

在3W规范中,我们采集音视频使用的API就是getUserMedia,但是google chrome实现的名字,是, firefox是

这样的话给前端开发带来很大麻烦,因为想要采集音视频数据,对于不同的浏览器厂商,就需要根据不同的浏览器做类型判断

而如果我们自己实现的话,就需要分别判断是否有合适的浏览器api,但是这种方式比较麻烦,可以用google的开源库适配不同的浏览器,为其定义统一的接口。

添加adapter后的index.html代码如下

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>WebRTC caoture video and audio</title>

</head>

<body>

       <!--video元素里可以显示我们捕获的音视频数据-->

       <!--autoplay属性表示我们拿到视频源的时候直接将它播放出来,playsinline 表示在浏览器的页面中播放-->

       <video  autoplay playsinline  id="player"></video>

       <!--引入adapter.js-->

       <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

       <!--加入一段javascript源码,通过调用  getusermedia这个api来捕获音视频数据,-->

       <script  src = './js/client.js'  ></script>

</body>

</html>

再次打开,查看网络,可以看到下载到的adapter源码

同时,在不同的浏览器中,我们都可以获取到视频流

 

6-3 获取音视频设备的访问权限

 

在前面获取到音视频设备信息的章节中,我们在chrome浏览器中可以获取到设备信息,而换到safari浏览器中却获取失败,这是因为没有获取到相应的权限。

解决这个问题,可以通过上小节我们提到的adapter.js 获取到音视频设备的权限。

代码如下:

index.html

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>WebRTC caoture video and audio</title>

</head>

<body>

       <!--音频源,音频是输出,视频源-->





       <div>

       <label>audio Source:</label>

       <select id = "audioSource"></select>

       </div>





       <div>

       <label>audio Output:</label>

       <select id = "audioOutput"></select>

       </div>



       <div>

       <label>video Source</label>

       <select id = "videoSource"></select>

       </div>



       <!--video元素里可以显示我们捕获的音视频数据-->

       <!--autoplay属性表示我们拿到视频源的时候直接将它播放出来,playsinline 表示在浏览器的页面中播放-->

       <video  autoplay playsinline  id="player"></video>

       <!--引入adapter.js-->

       <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

       <!--加入一段javascript源码,通过调用  getusermedia这个api来捕获音视频数据,-->

       <script  src = './js/client.js'  ></script>

</body>





</html>



clinet.js

'use strict'





//获取select这个元素中id为audioSource的元素

var audioSource = document.querySelector("select#audioSource");

var audioOutput = document.querySelector("select#audioOutput");

var videoSource = document.querySelector("select#videoSource");



//首先获取到在html中定义的vedio标签

var videoplay = document.querySelector('video#player');





//获取设备信息,参数是设备信息的数组

function gotDevices(deviceInfos) {

    //遍历设备信息数组

    deviceInfos.forEach(

        //拿到每一项的deviceInfo作为参数

       function (deviceinfo) {

           //select 中的每一项是一个option,根据不同的种类添加到不同的select中去

           var option = document.createElement('option');

           option.text = deviceinfo.label;  //设备名称

           option.value = deviceinfo.deviceId //值是deviceid

           console.log("deviceinfo.kind:",deviceinfo.kind);

           if(deviceinfo.kind === 'audioinput'){

               audioSource.appendChild(option);

           }else if(deviceinfo.kind === 'audiooutput'){

               audioOutput.appendChild(option);

           }else if(deviceinfo.kind === 'videoinput'){

               videoSource.appendChild(option);

           }

       }

    )

}





//实现获取流之后的方法,将获取到的流赋值给我们在html中定义的vedio标签

function gotMediaStream(stream) {

    //指定标签获取视频流的数据源

    videoplay.srcObject = stream;

    //拿到流之后,说明用户已经同意访问音视频设备了,此时可以返回一个promise,获取

    //所有的音视频设备

    return navigator.mediaDevices.enumerateDevices();

}





//获取失败 打印出错信息

function handleError(err) {

    console.log('getUserMedia error:', err);

}



//如果这个方法不存在,则打印

if(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia){

    console.log('getUserMedia is not supported!');

}else {

    //设置参数,同时采集音频和视频数组

    var constraints = {

            video:true,

            audio:true

    }

    //如果存在,就调用这个方法,成功进入成功方法,失败进入失败方法

    //成功之后,由于promise是可以串联的,then之后可以继续then

    navigator.mediaDevices.getUserMedia(constraints)

        .then(gotMediaStream)

        .then(gotDevices)

        .catch(handleError);

}

执行后打开浏览器查看效果

 

 

我们看到safari浏览器并不能获取到全部设备信息,有可能是音频输出设备不叫这个名字

 

6-4 视频约束 ( 视频参数调整 )

 

通过音视频的采集约束我们可以精确控制音视频的采集数据,首先是width即分辨率的宽是多少,第二个是height, 一般宽和高有两种比例,4:3, 16:9 , 

是比例,即宽除以高

 

frameRate 为帧率,我们可以通过帧率的多少来控制我们的码流,如果帧率低的话,会看到画面不太平滑,帧率高的话,画面就会很平滑,目前一般的高清电影都有60帧,另外一点,如果帧率过高的话,码流肯定会过大,相当于一秒钟采集的数据多,facingMode 用于控制摄像头翻转,主要用于手机摄像头。resizeMode 为采集的画面是否裁剪。

这些参数的设置方法如下:

//设置参数,只采集视频,并设置视频参数

var constraints = {

        video:{

            width:320,

            height:240,

            frameRate:30,

            facingMode:'enviroment'

        },

        audio:false

}

 

6-5 音频约束(音频参数设置)

volunme:声音大小,从0 到 1.0

sampleRate:采样率

sampleSize: 采样大小,一般情况下为16位,也就是2个字节

:回音,即采集数据之后,是否要开启回音消除

:自动增益,即在原有声音的基础上,是否增加音量 

 :降噪,即采集数据的时候,是否要开启降噪功能

latency:延迟大小,设置延迟小,而网络状况不好,就会出现卡顿,花屏等问题,好处是双方可以实时通信,一般是低于500毫秒, 最好是200毫秒内

channelCount:单声道还是双声道,一般情况下使用单声道就够了,如果是乐器,一般为双声道

deviceID:当有多个摄像头或者多个输入输出设备的时候,可以进行设备的切换

groupID:音频的输入与输出??

 

 

 

实战:修改后的clinet.js 代码如下

'use strict'





//获取select这个元素中id为audioSource的元素

var audioSource = document.querySelector("select#audioSource");

var audioOutput = document.querySelector("select#audioOutput");

var videoSource = document.querySelector("select#videoSource");



//首先获取到在html中定义的vedio标签

var videoplay = document.querySelector('video#player');





//获取设备信息,参数是设备信息的数组

function gotDevices(deviceInfos) {

    //遍历设备信息数组

    deviceInfos.forEach(

        //拿到每一项的deviceInfo作为参数

       function (deviceinfo) {

           //select 中的每一项是一个option,根据不同的种类添加到不同的select中去

           var option = document.createElement('option');

           option.text = deviceinfo.label;  //设备名称

           option.value = deviceinfo.deviceId //值是deviceid

           console.log("deviceinfo.kind:",deviceinfo.kind);

           if(deviceinfo.kind === 'audioinput'){

               audioSource.appendChild(option);

           }else if(deviceinfo.kind === 'audiooutput'){

               audioOutput.appendChild(option);

           }else if(deviceinfo.kind === 'videoinput'){

               videoSource.appendChild(option);

           }

       }

    )

}









//实现获取流之后的方法,将获取到的流赋值给我们在html中定义的vedio标签

function gotMediaStream(stream) {

    //指定标签获取视频流的数据源

    videoplay.srcObject = stream;

    //拿到流之后,说明用户已经同意访问音视频设备了,此时可以返回一个promise,获取

    //所有的音视频设备

    return navigator.mediaDevices.enumerateDevices();

}





//获取失败 打印出错信息

function handleError(err) {

    console.log('getUserMedia error:', err);

}













function start() {





//如果这个方法不存在,则打印

    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {

        console.log('getUserMedia is not supported!')

        return;

    } else {





        var deviceId = videoSource.value;





        //设置参数,采集音视频,并设置视频参数和音频参数

        var constraints = {

            video: {

                width: 320,

                height: 240,

                frameRate: 30,

                facingMode: 'enviroment',

                //判断deviceId的值是否为空,如果不为空就设置它的值为deviceId,如果为空就设置为undefined

                deviceId: deviceId ? deviceId: undefined

            },

            audio: {

                noiseSuppression: true,

                echoCancellation: true

            },





        }





        //如果存在,就调用这个方法,成功进入成功方法,失败进入失败方法

        //成功之后,由于promise是可以串联的,then之后可以继续then

        navigator.mediaDevices.getUserMedia(constraints)

            .then(gotMediaStream)

            .then(gotDevices)

            .catch(handleError);

    }

}





start();









//增加事件,选择摄像头的时候重新调用start函数,实现设备切换

videoSource.onchange = start;

 

6-6 视频特效

 

在浏览器中做特效使用的是 CSS filter,在不同浏览器中使用的filter还不一样。我们在视频渲染的时候,实际上在底层最终调用的还是OpenGL或者是Metal基础的图形绘制库,通过GPU进行绘制。

实战:

index.html









<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>WebRTC caoture video and audio</title>

       <style>

              .none {

                      -webkit-filter: none;

              }





              .blur {

                      -webkit-filter: blur(3px);

              }





              .grayscale {

                      -webkit-filter: grayscale(1);

              }





              .invert {

                      -webkit-filter: invert(1);

              }





              .sepia {

                      -webkit-filter: sepia(1);

              }





       </style>





</head>

<body>

       <!--音频源,音频是输出,视频源-->





       <div>

       <label>audio Source:</label>

       <select id = "audioSource"></select>

       </div>





       <div>

       <label>audio Output:</label>

       <select id = "audioOutput"></select>

       </div>





       <div>

       <label>video Source</label>

       <select id = "videoSource"></select>

       </div>









       <div>

               <label>Filter: </label>

              <select id="filter">

                     <option value="none">None</option>

                     <option value="blur">blur</option>

                     <option value="grayscale">Grayscale</option>

                     <option value="invert">Invert</option>

                     <option value="sepia">sepia</option>

              </select>

       </div>





       <!--video元素里可以显示我们捕获的音视频数据-->

       <!--autoplay属性表示我们拿到视频源的时候直接将它播放出来,playsinline 表示在浏览器的页面中播放-->

       <video  autoplay playsinline  id="player"></video>

       <!--引入adapter.js-->

       <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

       <!--加入一段javascript源码,通过调用  getusermedia这个api来捕获音视频数据,-->

       <script  src = './js/client.js'  ></script>

</body>





</html>



client.js





'use strict'





//获取select这个元素中id为audioSource的元素

var audioSource = document.querySelector("select#audioSource");

var audioOutput = document.querySelector("select#audioOutput");

var videoSource = document.querySelector("select#videoSource");

var filtersSelect = document.querySelector("select#filter");









//首先获取到在html中定义的vedio标签

var videoplay = document.querySelector('video#player');





//获取设备信息,参数是设备信息的数组

function gotDevices(deviceInfos) {

    //遍历设备信息数组

    deviceInfos.forEach(

        //拿到每一项的deviceInfo作为参数

       function (deviceinfo) {

           //select 中的每一项是一个option,根据不同的种类添加到不同的select中去

           var option = document.createElement('option');

           option.text = deviceinfo.label;  //设备名称

           option.value = deviceinfo.deviceId //值是deviceid

           console.log("deviceinfo.kind:",deviceinfo.kind);

           if(deviceinfo.kind === 'audioinput'){

               audioSource.appendChild(option);

           }else if(deviceinfo.kind === 'audiooutput'){

               audioOutput.appendChild(option);

           }else if(deviceinfo.kind === 'videoinput'){

               videoSource.appendChild(option);

           }

       }

    )

}









//实现获取流之后的方法,将获取到的流赋值给我们在html中定义的vedio标签

function gotMediaStream(stream) {

    //指定标签获取视频流的数据源

    videoplay.srcObject = stream;

    //拿到流之后,说明用户已经同意访问音视频设备了,此时可以返回一个promise,获取

    //所有的音视频设备

    return navigator.mediaDevices.enumerateDevices();

}





//获取失败 打印出错信息

function handleError(err) {

    console.log('getUserMedia error:', err);

}













function start() {





//如果这个方法不存在,则打印

    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {

        console.log('getUserMedia is not supported!')

        return;

    } else {





        var deviceId = videoSource.value;





        //设置参数,采集音视频,并设置视频参数和音频参数

        var constraints = {

            video: {

                width: 320,

                height: 240,

                frameRate: 30,

                facingMode: 'enviroment',

                //判断deviceId的值是否为空,如果不为空就设置它的值为deviceId,如果为空就设置为undefined

                deviceId: deviceId ? deviceId: undefined

            },

            audio: {

                noiseSuppression: true,

                echoCancellation: true

            },





        }





        //如果存在,就调用这个方法,成功进入成功方法,失败进入失败方法

        //成功之后,由于promise是可以串联的,then之后可以继续then

        navigator.mediaDevices.getUserMedia(constraints)

            .then(gotMediaStream)

            .then(gotDevices)

            .catch(handleError);

    }

}





start();









//增加事件,选择摄像头的时候重新调用start函数,实现设备切换

videoSource.onchange = start;

//增加事件处理,当我们选择其中的某一项变化的时候,进行处理

//onchange 事件会在域的内容改变时发生

filtersSelect.onchange = function () {

    //获取视频的模式的名字

    videoplay.className = filtersSelect.value;





}

效果:

 

 

 

 

注意,如果更新代码后,开启浏览器发现没有获取到音视频设备,可以尝试重启电脑

 

6-7 从视频中获取图片 实战

index.html









<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>WebRTC caoture video and audio</title>

       <style>

              .none {

                      -webkit-filter: none;

              }





              .blur {

                      -webkit-filter: blur(3px);

              }





              .grayscale {

                      -webkit-filter: grayscale(1);

              }





              .invert {

                      -webkit-filter: invert(1);

              }





              .sepia {

                      -webkit-filter: sepia(1);

              }





       </style>





</head>

<body>

       <!--音频源,音频是输出,视频源-->





       <div>

       <label>audio Source:</label>

       <select id = "audioSource"></select>

       </div>





       <div>

       <label>audio Output:</label>

       <select id = "audioOutput"></select>

       </div>





       <div>

       <label>video Source</label>

       <select id = "videoSource"></select>

       </div>









       <div>

               <label>Filter: </label>

              <select id="filter">

                     <option value="none">None</option>

                     <option value="blur">blur</option>

                     <option value="grayscale">Grayscale</option>

                     <option value="invert">Invert</option>

                     <option value="sepia">sepia</option>

              </select>

       </div>





       <!--video元素里可以显示我们捕获的音视频数据-->

       <!--autoplay属性表示我们拿到视频源的时候直接将它播放出来,playsinline 表示在浏览器的页面中播放-->

       <video  autoplay playsinline  id="player"></video>

       <div>

           <button id="snapshot">Take snapshot</button>

       </div>

       <div>

           <canvas id="picture"></canvas>

       </div>









       <!--引入adapter.js-->

       <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

       <!--加入一段javascript源码,通过调用  getusermedia这个api来捕获音视频数据,-->

       <script  src = './js/client.js'  ></script>





</body>





</html>

client.js





'use strict'





//获取select这个元素中id为audioSource的元素

var audioSource = document.querySelector("select#audioSource");

var audioOutput = document.querySelector("select#audioOutput");

var videoSource = document.querySelector("select#videoSource");

//filter

var filtersSelect = document.querySelector("select#filter");









//picture

var snapshot = document.querySelector('button#snapshot');

var picture = document.querySelector('canvas#picture');

picture.width = 320;

picture.height = 240;













//首先获取到在html中定义的vedio标签

var videoplay = document.querySelector('video#player');









//获取设备信息,参数是设备信息的数组

function gotDevices(deviceInfos) {

    //遍历设备信息数组

    deviceInfos.forEach(

        //拿到每一项的deviceInfo作为参数

       function (deviceinfo) {

           //select 中的每一项是一个option,根据不同的种类添加到不同的select中去

           var option = document.createElement('option');

           option.text = deviceinfo.label;  //设备名称

           option.value = deviceinfo.deviceId //值是deviceid

           console.log("deviceinfo.kind:",deviceinfo.kind);

           if(deviceinfo.kind === 'audioinput'){

               audioSource.appendChild(option);

           }else if(deviceinfo.kind === 'audiooutput'){

               audioOutput.appendChild(option);

           }else if(deviceinfo.kind === 'videoinput'){

               videoSource.appendChild(option);

           }

       }

    )

}









//实现获取流之后的方法,将获取到的流赋值给我们在html中定义的vedio标签

function gotMediaStream(stream) {

    //指定标签获取视频流的数据源

    videoplay.srcObject = stream;

    //拿到流之后,说明用户已经同意访问音视频设备了,此时可以返回一个promise,获取

    //所有的音视频设备

    return navigator.mediaDevices.enumerateDevices();

}





//获取失败 打印出错信息

function handleError(err) {

    console.log('getUserMedia error:', err);

}













function start() {





//如果这个方法不存在,则打印

    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {

        console.log('getUserMedia is not supported!')

        return;

    } else {





        var deviceId = videoSource.value;





        //设置参数,采集音视频,并设置视频参数和音频参数

        var constraints = {

            video: {

                width: 320,

                height: 240,

                frameRate: 30,

                facingMode: 'enviroment',

                //判断deviceId的值是否为空,如果不为空就设置它的值为deviceId,如果为空就设置为undefined

                deviceId: deviceId ? deviceId: undefined

            },

            audio: {

                noiseSuppression: true,

                echoCancellation: true

            },





        }





        //如果存在,就调用这个方法,成功进入成功方法,失败进入失败方法

        //成功之后,由于promise是可以串联的,then之后可以继续then

        navigator.mediaDevices.getUserMedia(constraints)

            .then(gotMediaStream)

            .then(gotDevices)

            .catch(handleError);

    }

}





start();









//增加事件,选择摄像头的时候重新调用start函数,实现设备切换

videoSource.onchange = start;

//增加事件处理,当我们选择其中的某一项变化的时候,进行处理

//onchange 事件会在域的内容改变时发生

filtersSelect.onchange = function () {

    //获取视频的模式的名字

    videoplay.className = filtersSelect.value;





}





//给snapshot添加onclick事件,当我们点击button的时候,触发这个事件

snapshot.onclick =  function () {

    //设置滤镜

    picture.className = filtersSelect.value;

    //得到picture的上下文,将videoplay当成源,从这里截取一帧数据,写成一张图片

    picture.getContext('2d').drawImage(videoplay,

                                         0,0,

                                         picture.width,

                                         picture.height);

}

效果:

6-8 webrtc只采集音频数据 实战

index.html









<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>WebRTC caoture video and audio</title>

       <style>

              .none {

                      -webkit-filter: none;

              }





              .blur {

                      -webkit-filter: blur(3px);

              }





              .grayscale {

                      -webkit-filter: grayscale(1);

              }





              .invert {

                      -webkit-filter: invert(1);

              }





              .sepia {

                      -webkit-filter: sepia(1);

              }





       </style>





</head>

<body>

       <!--音频源,音频是输出,视频源-->





       <div>

       <label>audio Source:</label>

       <select id = "audioSource"></select>

       </div>





       <div>

       <label>audio Output:</label>

       <select id = "audioOutput"></select>

       </div>





       <div>

       <label>video Source</label>

       <select id = "videoSource"></select>

       </div>









       <div>

               <label>Filter: </label>

              <select id="filter">

                     <option value="none">None</option>

                     <option value="blur">blur</option>

                     <option value="grayscale">Grayscale</option>

                     <option value="invert">Invert</option>

                     <option value="sepia">sepia</option>

              </select>

       </div>





       <!--增加audio标签,只采集音频数据, controls会将暂停和播放按钮显示出来-->

       <audio  autoplay     controls id="audioplayer"></audio>

       <!--video元素里可以显示我们捕获的音视频数据-->

       <!--autoplay属性表示我们拿到视频源的时候直接将它播放出来,playsinline 表示在浏览器的页面中播放-->

       <!--<video  autoplay playsinline  id="player"></video>-->

       <div>

           <button id="snapshot">Take snapshot</button>

       </div>

       <div>

           <canvas id="picture"></canvas>

       </div>









       <!--引入adapter.js-->

       <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

       <!--加入一段javascript源码,通过调用  getusermedia这个api来捕获音视频数据,-->

       <script  src = './js/client.js'  ></script>





</body>





</html>

client.js





'use strict'





//获取select这个元素中id为audioSource的元素

var audioSource = document.querySelector("select#audioSource");

var audioOutput = document.querySelector("select#audioOutput");

var videoSource = document.querySelector("select#videoSource");

//filter

var filtersSelect = document.querySelector("select#filter");









//picture

var snapshot = document.querySelector('button#snapshot');

var picture = document.querySelector('canvas#picture');

picture.width = 320;

picture.height = 240;









//获取音频

var audioplay = document.querySelector('audio#audioplayer')









//首先获取到在html中定义的vedio标签,从而获取视频

// var videoplay = document.querySelector('video#player');









//获取设备信息,参数是设备信息的数组

function gotDevices(deviceInfos) {

    //遍历设备信息数组

    deviceInfos.forEach(

        //拿到每一项的deviceInfo作为参数

       function (deviceinfo) {

           //select 中的每一项是一个option,根据不同的种类添加到不同的select中去

           var option = document.createElement('option');

           option.text = deviceinfo.label;  //设备名称

           option.value = deviceinfo.deviceId //值是deviceid

           console.log("deviceinfo.kind:",deviceinfo.kind);

           if(deviceinfo.kind === 'audioinput'){

               audioSource.appendChild(option);

           }else if(deviceinfo.kind === 'audiooutput'){

               audioOutput.appendChild(option);

           }else if(deviceinfo.kind === 'videoinput'){

               videoSource.appendChild(option);

           }

       }

    )

}









//实现获取流之后的方法,将获取到的流赋值给我们在html中定义的vedio标签

function gotMediaStream(stream) {

    //指定标签获取视频流的数据源

    // videoplay.srcObject = stream;

    audioplay.srcObject = stream;





    //拿到流之后,说明用户已经同意访问音视频设备了,此时可以返回一个promise,获取

    //所有的音视频设备

    return navigator.mediaDevices.enumerateDevices();

}





//获取失败 打印出错信息

function handleError(err) {

    console.log('getUserMedia error:', err);

}













function start() {





//如果这个方法不存在,则打印

    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {

        console.log('getUserMedia is not supported!')

        return;

    } else {





        var deviceId = videoSource.value;





        //设置参数,采集音视频,并设置视频参数和音频参数

        var constraints = {

            // video: {

            //     width: 320,

            //     height: 240,

            //     frameRate: 30,

            //     facingMode: 'enviroment',

            //     //判断deviceId的值是否为空,如果不为空就设置它的值为deviceId,如果为空就设置为undefined

            //     deviceId: deviceId ? deviceId: undefined

            // },

            vedio:false,

            audio: {

                noiseSuppression: true,

                echoCancellation: true

            },





        }





        //如果存在,就调用这个方法,成功进入成功方法,失败进入失败方法

        //成功之后,由于promise是可以串联的,then之后可以继续then

        navigator.mediaDevices.getUserMedia(constraints)

            .then(gotMediaStream)

            .then(gotDevices)

            .catch(handleError);

    }

}





start();









//增加事件,选择摄像头的时候重新调用start函数,实现设备切换

videoSource.onchange = start;

//增加事件处理,当我们选择其中的某一项变化的时候,进行处理

//onchange 事件会在域的内容改变时发生

filtersSelect.onchange = function () {

    //获取视频的模式的名字

    videoplay.className = filtersSelect.value;





}





//给snapshot添加onclick事件,当我们点击button的时候,触发这个事件

snapshot.onclick =  function () {

    //设置滤镜

    picture.className = filtersSelect.value;

    //得到picture的上下文,将videoplay当成源,从这里截取一帧数据,写成一张图片

    picture.getContext('2d').drawImage(videoplay,

                                         0,0,

                                         picture.width,

                                         picture.height);

}

效果:

6-9 MediaStreamAPI及获取视频约束

:向媒体流中加入不同的轨

:从媒体流中将不想要的轨移除

:拿到所有视频的轨

:拿到媒体流中所有音频的track

:添加一个媒体轨到媒体流的时候会触发这个事件

:移除一个媒体轨到媒体流的时候会触发这个事件

:当一个流结束的时候,会收到流结束的事件

实战:

 

index.html









<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>WebRTC caoture video and audio</title>

       <style>

              .none {

                      -webkit-filter: none;

              }





              .blur {

                      -webkit-filter: blur(3px);

              }





              .grayscale {

                      -webkit-filter: grayscale(1);

              }





              .invert {

                      -webkit-filter: invert(1);

              }





              .sepia {

                      -webkit-filter: sepia(1);

              }





       </style>





</head>

<body>

       <!--音频源,音频是输出,视频源-->





       <div>

       <label>audio Source:</label>

       <select id = "audioSource"></select>

       </div>





       <div>

       <label>audio Output:</label>

       <select id = "audioOutput"></select>

       </div>





       <div>

       <label>video Source</label>

       <select id = "videoSource"></select>

       </div>









       <div>

               <label>Filter: </label>

              <select id="filter">

                     <option value="none">None</option>

                     <option value="blur">blur</option>

                     <option value="grayscale">Grayscale</option>

                     <option value="invert">Invert</option>

                     <option value="sepia">sepia</option>

              </select>

       </div>





       <!--增加audio标签,只采集音频数据, controls会将暂停和播放按钮显示出来-->

<!--       <audio  autoplay controls id="audioplayer"></audio>-->





       <section>

       <table>

              <tr>

       <!--video元素里可以显示我们捕获的音视频数据-->

       <!--autoplay属性表示我们拿到视频源的时候直接将它播放出来,playsinline 表示在浏览器的页面中播放-->

       <!-- 一行两列,第一列显示捕获的视频,第二列显示视频约束-->

           <td> <video  autoplay playsinline  id="player"></video></td>

           <td><div id="constraints" class="output"></div></td>

              </tr>

       </table>

       </section>

       <div>

              <button id="snapshot">Take snapshot</button>

           <canvas id="picture"></canvas>

       </div>









       <!--引入adapter.js-->

       <script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>

       <!--加入一段javascript源码,通过调用  getusermedia这个api来捕获音视频数据,-->

       <script  src = './js/client.js'  ></script>





</body>





</html>

client.js





'use strict'





//获取select这个元素中id为audioSource的元素

var audioSource = document.querySelector("select#audioSource");

var audioOutput = document.querySelector("select#audioOutput");

var videoSource = document.querySelector("select#videoSource");

//filter

var filtersSelect = document.querySelector("select#filter");









//picture

var snapshot = document.querySelector('button#snapshot');

var picture = document.querySelector('canvas#picture');

picture.width = 320;

picture.height = 240;









//获取音频

//var audioplay = document.querySelector('audio#audioplayer')









//首先获取到在html中定义的vedio标签,从而获取视频

var videoplay = document.querySelector('video#player');





//获取到 divConstraints

var divConstraints = document.querySelector('div#constraints');





//获取设备信息,参数是设备信息的数组

function gotDevices(deviceInfos) {

    //遍历设备信息数组

    deviceInfos.forEach(

        //拿到每一项的deviceInfo作为参数

       function (deviceinfo) {

           //select 中的每一项是一个option,根据不同的种类添加到不同的select中去

           var option = document.createElement('option');

           option.text = deviceinfo.label;  //设备名称

           option.value = deviceinfo.deviceId //值是deviceid

           console.log("deviceinfo.kind:",deviceinfo.kind);

           if(deviceinfo.kind === 'audioinput'){

               audioSource.appendChild(option);

           }else if(deviceinfo.kind === 'audiooutput'){

               audioOutput.appendChild(option);

           }else if(deviceinfo.kind === 'videoinput'){

               videoSource.appendChild(option);

           }

       }

    )

}









//实现获取流之后的方法,将获取到的流赋值给我们在html中定义的vedio标签

function gotMediaStream(stream) {

    //指定标签获取视频流的数据源

    videoplay.srcObject = stream;

    //通过media stream 拿到视频的track,视频轨,只取第一个

    var videoTrack = stream.getVideoTracks()[0];

    //拿到vedio的所有约束

    var videoConstraints = videoTrack.getSettings();

    //将其转成json格式,作为内容赋值给divConstraints,在页面展示出来

    divConstraints.textContent =   JSON.stringify(videoConstraints,null,2);





    //audioplay.srcObject = stream;





    //拿到流之后,说明用户已经同意访问音视频设备了,此时可以返回一个promise,获取

    //所有的音视频设备

    return navigator.mediaDevices.enumerateDevices();

}





//获取失败 打印出错信息

function handleError(err) {

    console.log('getUserMedia error:', err);

}





function start() {





//如果这个方法不存在,则打印

    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {

        console.log('getUserMedia is not supported!')

        return;

    } else {





        var deviceId = videoSource.value;





        //设置参数,采集音视频,并设置视频参数和音频参数

        var constraints = {

            video: {

                width: 320,

                height: 240,

                frameRate: 30,

                facingMode: 'enviroment',

                //判断deviceId的值是否为空,如果不为空就设置它的值为deviceId,如果为空就设置为undefined

                deviceId: deviceId ? deviceId: undefined

            },

            // vedio:false,

            audio: {

                noiseSuppression: true,

                echoCancellation: true

            },





        }





        //如果存在,就调用这个方法,成功进入成功方法,失败进入失败方法

        //成功之后,由于promise是可以串联的,then之后可以继续then

        navigator.mediaDevices.getUserMedia(constraints)

            .then(gotMediaStream)

            .then(gotDevices)

            .catch(handleError);

    }

}





start();









//增加事件,选择摄像头的时候重新调用start函数,实现设备切换

videoSource.onchange = start;

//增加事件处理,当我们选择其中的某一项变化的时候,进行处理

//onchange 事件会在域的内容改变时发生

filtersSelect.onchange = function () {

    //获取视频的模式的名字

    videoplay.className = filtersSelect.value;





}





//给snapshot添加onclick事件,当我们点击button的时候,触发这个事件

snapshot.onclick =  function () {

    //设置滤镜

    picture.className = filtersSelect.value;

    //得到picture的上下文,将videoplay当成源,从这里截取一帧数据,写成一张图片

    picture.getContext('2d').drawImage(videoplay,

                                         0,0,

                                         picture.width,

                                         picture.height);

}

效果:

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值