5.3 采集音视频数据

通过enumerateDevices()接口获得音视频设备后,就可以选择其中的设备进行数据采集了。在浏览器下采集音视频数据也很方便,调用getUserMedia()这个API就可以采集到。getUserMedia的接口格式如代码5.4所示。

代码5.4 getUserMedia()接口格式


navigator.mediaDevices.
      getUserMedia(MediaStreamConstrains);

该接口有一个MediaStreamConstrains类型的输入参数,可以用来控制从哪个设备上采集音视频数据,以及限制采集到的数据的格式,如限制采集到的视频分辨率、音频数据的采样率、采样大小等。其结构如代码5.5所示。

代码5.5 MediaStreamConstrains结构体


dictionary MediaStreamConstrains {
   (boolean) or (MediaTrackConstrains) video = false;
   (boolean) or (MediaTrackConstrains) audio = false;
}

从上面MediaStreamConstrains类型的定义可以看出,video和audio属性既可以是boolean类型,也可以是MediaTrackConstrains类型(只有像JavaScript这种弱类型语言才可以做这一点)。因此,我们既可以直接给video和audio赋值true/false,简单地指明是否采集视频或音频数据,也可以给它赋值一个MediaTrackConstrains类型的值,对音视频设备做更精准的设置。

如果直接给video/audio属性赋值true,则浏览器会使用默认设备和默认参数采集音视频数据,否则如果给video/audio赋值MediaTrackConstrains类型值,则浏览器会按MediaTrackConstrains中的限制,从指定的设备中采集音视频数据。MediaTrackConstrains结构如代码5.6所示。

代码5.6 MediaTrackConstraintSet结构体


dictionary MediaTrackConstraintSet {
   //视频相关
   ConstrainULong width;
   ConstrainULong height;
   ConstrainDouble aspectRatio;//宽高比
   ConstrainDouble frameRate;
   ConstrainDOMString facingMode; //前置/后置摄像头
   ConstrainDOMString resizeMode; //缩放或裁剪
   //音频相关
   ConstrainULong sampleRate;
   ConstrainULong sampleSize;
   ConstrainBoolean echoCancellation;
   ConstrainBoolean autoGainControl;
   ConstrainBoolean noiseSuppression;
   ConstrainDouble latency;//目标延迟
   ConstrainULong channelCount;
   //设备相关
   ConstrainDOMString deviceId;
   ConstrainDOMString groupId;
};

从上面的代码片段中可以看到,MediaTrackConstrains结构由三部分组成,即视频相关属性、音频相关属性以及设备相关属性。视频属性中包括分辨率、视频宽高比、帧率、前置/后置摄像头、视频缩放;音频属性包括采样率、采样大小、是否开启回音消除、是否开启自动增益、是否开启降噪、目标延迟、声道数;设备相关属性包括设备ID、设备组ID。

我们来看一个具体的例子,看看如何通过getUserMedia()接口来采集音视频数据。具体代码参见代码5.7。

代码5.7 获取音视频流


1 // 采集到某路流
2 function gotMediaStream(stream){
3    …
4 }
5 …
6 // 从设备选项栏里选择某个设备
7 var deviceId = xxx;
8
9 // 设置采集限制
10 var constraints = {
11   video : {
12      width: 640,
13      height: 480,
14      frameRate  :  15 ,
15      facingMode  : 'enviroment ',
16      deviceId  :  deviceId ?{ exact:deviceId }: undefined
17   },
18   audio : false
19 }
20
21 // 开始采集数据
22 navigator.mediaDevices.getUserMedia(constraints)  
23     .then(gotMediaStream)
24     .catch(handleError);
25 …

在上面的代码片段中,首先执行第22行代码,即调用getUserMedia()接口,然后根据constraints中的限制获取音视频数据。在这个例子中,getUserMedia()从指定设备(deviceId)上按指定参数采集视频数据,具体参数如下:分辨率为640×480、帧率为15帧/秒、使用后置摄像头(environment https://w3c.github.io/mediacapture-main/#def-constraint-facingMode)。因为audio属性为false,所以此例中仅采集视频数据而不采集音频数据。

此外,从上面的代码中还可以看到,调用getUserMedia()接口的方式与调用enumerate Devices()接口的方式是一样的,也是使用Promise方式。当调用getUserMedia()成功时,会回调gotMediaStream()函数,该函数的输入参数MediaStream里存放的就是音视频数据流。当获得音视频数据后,既可以把它作为本地预览,也可以将它传送给远端,从而实现一对一通信。如果调用getUserMedia()接口失败,则调用错误处理函数handleError。

[1] https://w3c.github.io/mediacapture-main/#def-constraint-facingMode