5.3 分辨率设置
在WebRTC中,分辨率的设置是通过获取视频时传递约束条件来控制的,如下面的代码所示,表示要设置成一个高清720P的分辨率。这样当调用getUserMedia()时会采用1280×720的尺寸采集。
//高清约束条件 const hdConstraints = { //视频 video: { //宽 width: { exact: 1280 }, //高 height: { exact: 720 } } };
接下来通过一个示例来详细阐述如何设置不同的分辨率。具体步骤如下。
步骤1 打开h5-samples工程下的src目录,添加Resolution.jsx文件。添加QVGA、VGA、720P、1080P、2K、4K以及8K的约束条件。以QVGA为例,代码如下所示。
//QVGA 320*240 const qvgaConstraints = { video: { width: { exact: 320 }, height: { exact: 240 } } };
步骤2 编写根据不同约束条件获取视频流的方法,这里的约束代表了不同的分辨率。在重新获取视频之前,需要把当前stream里的所有流都停掉。大致处理如下所示。
//根据约束获取视频 getMedia = (constraints) => { ... //迭代并停止所有轨道 stream.getTracks().forEach(track => { track.stop(); }); //重新获取视频 navigator.mediaDevices.getUserMedia(constraints) ... }
流中通常是有多个轨道的,可以使用forEach将其所有轨道迭代出来,然后调用stop方法停止。
步骤3 当获取到流后,将流传递给video对象渲染出来即可。代码如下所示。
gotStream = (mediaStream) => { stream = window.stream = mediaStream; //将video视频源指定为mediaStream video.srcObject = mediaStream; }
步骤4 编写下拉列表框回调方法,根据选中的项传递不同的约束,代码大致如下所示。
//传递QVGA约束 getMedia(qvgaConstraints); //传递VGA约束 getMedia(vgaConstraints); ... //传递高清约束 getMedia(hdConstraints);
步骤5 上述方法每次改变分辨率时都需要重新调用getUserMedia()方法,这样需要重新请求访问摄像头。还有另一种方法可以动态改变分辨率。关键代码如下所示。
dynamicChange = (e) => { //获取当前的视频流中的视频轨道 const track = window.stream.getVideoTracks()[0]; ... //改变轨道的约束条件 track.applyConstraints(constraints) ... }
这里使用了MediaStreamTrack的applyConstraints()方法,此方法可以动态改变约束条件。打开https://developer.mozilla.org/zh-CN/docs/Web/API/MediaStreamTrack网址可以查看详细使用说明。
步骤6 在页面渲染部分添加video标签、分辨率下拉列表框等界面元素,然后在src目录下的App.jsx及Samples.jsx里加上链接及路由绑定,这可参考第3章。完整的代码如下所示。
import React from "react"; import { Button, Select } from "antd"; const { Option } = Select; //QVGA 320*240 const qvgaConstraints = { video: { width: { exact: 320 }, height: { exact: 240 } } }; //VGA 640*480 const vgaConstraints = { video: { width: { exact: 640 }, height: { exact: 480 } } }; //高清 1280*720 const hdConstraints = { video: { width: { exact: 1280 }, height: { exact: 720 } } }; //超清 1920*1080 const fullHdConstraints = { video: { width: { exact: 1920 }, height: { exact: 1080 } } }; //2K 2560*1440 const twoKConstraints = { video: { width: { exact: 2560 }, height: { exact: 1440 } } }; //4K 4096*2160 const fourKConstraints = { video: { width: { exact: 4096 }, height: { exact: 2160 } } }; //8K 7680*4320 const eightKConstraints = { video: { width: { exact: 7680 }, height: { exact: 4320 } } }; //视频流 let stream; //视频对象 let video; /** * 分辨率示例 */ class Resolution extends React.Component { componentDidMount() { //获取video对象引用 video = this.refs['video']; } //根据约束获取视频 getMedia = (constraints) => { //判断流对象是否为空 if (stream) { //迭代并停止所有轨道 stream.getTracks().forEach(track => { track.stop(); }); } //重新获取视频 navigator.mediaDevices.getUserMedia(constraints) //成功获取 .then(this.gotStream) //错误 .catch(e => { this.handleError(e); }); } //得到视频流处理 gotStream = (mediaStream) => { stream = window.stream = mediaStream; //将video视频源指定为mediaStream video.srcObject = mediaStream; const track = mediaStream.getVideoTracks()[0]; const constraints = track.getConstraints(); console.log('约束条件为:' + JSON.stringify(constraints)); } //错误处理 handleError(error) { console.log(`getUserMedia错误: ${error.name}`, error); } //下拉列表框中的选项改变 handleChange = (value) => { console.log(`selected ${value}`); //根据下拉列表框的值获取不同分辨率的视频 switch (value) { case 'qvga': this.getMedia(qvgaConstraints); break; case 'vga': this.getMedia(vgaConstraints); break; case 'hd': this.getMedia(hdConstraints); break; case 'fullhd': this.getMedia(fullHdConstraints); break; case '2k': this.getMedia(twoKConstraints); break; case '4k': this.getMedia(fourKConstraints); break; case '8k': this.getMedia(eightKConstraints); break; default: this.getMedia(vgaConstraints); break; } } //动态改变分辨率 dynamicChange = (e) => { //获取当前视频流中的视频轨道 const track = window.stream.getVideoTracks()[0]; //使用超清约束作为测试条件 console.log('应用高清效果:' + JSON.stringify(hdConstraints)); track.applyConstraints(constraints) .then(() => { console.log('动态改变分辨率成功...'); }) .catch(err => { console.log('动态改变分辨率错误:', err.name); }); } render() { return ( <div className="container"> <h1> <span>视频分辨率示例</span> </h1> {/* 视频渲染 */} <video ref='video' playsInline autoPlay></video> {/* 清晰度选择 */} <Select defaultValue="vga" style={{ width: '100px',marginLeft:'20px' }} onChange={this.handleChange}> <Option value="qvga">QVGA</Option> <Option value="vga">VGA</Option> <Option value="hd">高清</Option> <Option value="fullhd">超清</Option> <Option value="2k">2K</Option> <Option value="4k">4K</Option> <Option value="8k">8K</Option> </Select> <Button onClick={this.dynamicChange} style={{ marginLeft:'20px' }}>动态设置</Button> </div> ); } } //导出组件 export default Resolution;
运行程序后,打开视频分辨率示例,点击下拉列表框可以选择不同的分辨率,运行效果如图5-1所示。
图5-1 视频分辨率切换
如果你的显示器或摄像头不支持某分辨率,则会报错。以笔者的笔记本为例,2K、4K以及8K是不支持的,这样就会报OverconstrainedError错误,控制台输出的内容如下所示。
getUserMedia错误: OverconstrainedError OverconstrainedError {name: "OverconstrainedError", message: null, constraint: "width"}
当控制台输出OverconstrainedError错误时,表示硬件无法满足约束条件,此时可以通过升级硬件或降低约束条件来解决这个问题。
当点击“动态设置”按钮时,也会切换用户分辨率,输出内容如下。
应用高清效果:{"video":{"width":{"exact":1280},"height":{"exact":720}}} Resolution.jsx:130 动态改变分辨率成功...