通过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);
}
效果: